『攻防世界』:進階區 | stack2
阿新 • • 發佈:2020-08-11
checksec:
Arch: i386-32-little RELRO: Partial RELRO Stack: Canary found NX: NX enabled PIE: No PIE (0x8048000)
IDA靜態分析:
int __cdecl main(int argc, const char **argv, const char **envp) { unsigned int v3; // eax unsigned int v5; // [esp-90h] [ebp-90h] unsigned intmainv6; // [esp-8Ch] [ebp-8Ch] int v7; // [esp-88h] [ebp-88h] unsigned int j; // [esp-84h] [ebp-84h] signed int v9; // [esp-80h] [ebp-80h] signed int i; // [esp-7Ch] [ebp-7Ch] unsigned int k; // [esp-78h] [ebp-78h] unsigned int l; // [esp-74h] [ebp-74h] int v13; // [esp-70h] [ebp-70h] unsigned int v14; // [esp-Ch] [ebp-Ch]v14 = __readgsdword(0x14u); setvbuf(stdin, 0, 2, 0); setvbuf(stdout, 0, 2, 0); v9 = 0; puts("***********************************************************"); puts("* An easy calc *"); puts("*Give me your numbers and I will return to you an average *"); puts("*(0 <= x < 256) *"); puts("***********************************************************"); puts("How many numbers you have:"); __isoc99_scanf("%d", &v5); puts("Give me your numbers"); for ( i = 0; i < v5 && i <= 99; ++i ) { __isoc99_scanf("%d", &v7); *((_BYTE *)&v13 + i) = v7; } for ( j = v5; ; printf("average is %.2lf\n", (double)((long double)v9 / (double)j)) ) { while ( 1 ) { while ( 1 ) { while ( 1 ) { puts("1. show numbers\n2. add number\n3. change number\n4. get average\n5. exit"); __isoc99_scanf("%d", &v6); if ( v6 != 2 ) break; puts("Give me your number"); __isoc99_scanf("%d", &v7); if ( j <= 0x63 ) { v3 = j++; *((_BYTE *)&v13 + v3) = v7; } } if ( v6 > 2 ) break; if ( v6 != 1 ) return 0; puts("id\t\tnumber"); for ( k = 0; k < j; ++k ) printf("%d\t\t%d\n", k, *((char *)&v13 + k)); } if ( v6 != 3 ) break; puts("which number to change:"); __isoc99_scanf("%d", &v5); puts("new number:"); __isoc99_scanf("%d", &v7); *((_BYTE *)&v13 + v5) = v7; } if ( v6 != 4 ) break; v9 = 0; for ( l = 0; l < j; ++l ) v9 += *((char *)&v13 + l); } return 0; }
這道題漏洞讓我好找,找了好久也不知道漏洞在哪,去網上找(chao)了一些思路,本題的棧溢位並不是常規的read這種輸入輸出流,而是因為對v5沒有任何檢測,陣列沒有邊界檢查導致的,這樣的棧溢位比較隱蔽。在第三個選項,change number裡v13定義為char v13[100],但是在這裡並沒有邊界的檢查導致棧溢位。題目中已近有現成的後門函式(0x0804859B)。
int hackhere() { return system("/bin/bash"); }hackhere
原理很清楚,只要選changenumber就可以修改任意地址的資料,我們只要找到v13資料距離ret的距離,就可以獲取shell。
經過下面的除錯,可以發現ebp=v13+0x70,ret=v13+0x84。由於程式中有函式hackhere可以直接呼叫system,所以修改ret的地址為hackhere的地址即可。
首先要知道v13陣列的一個引數存放的位置:
.text:08048698 push offset asc_8048A9A ; "Give me your numbers" .text:0804869D call _puts .text:080486A2 add esp, 10h .text:080486A5 mov dword ptr [ebp-7Ch], 0 .text:080486AC jmp short loc_80486DB .text:080486AE ; --------------------------------------------------------------------------- .text:080486AE .text:080486AE loc_80486AE: ; CODE XREF: main+11C↓j .text:080486AE sub esp, 8 .text:080486B1 lea eax, [ebp-88h] .text:080486B7 push eax .text:080486B8 push offset asc_8048A97 ; "%d" .text:080486BD call ___isoc99_scanf .text:080486C2 add esp, 10h .text:080486C5 mov eax, [ebp-88h] .text:080486CB mov ecx, eax .text:080486CD lea edx, [ebp-70h] .text:080486D0 mov eax, [ebp-7Ch] .text:080486D3 add eax, edx .text:080486D5 mov [eax], cl .text:080486D7 add dword ptr [ebp-7Ch], 1first input
其中var-88是我們第一個輸入的數字,並且他被存放到eax中,使用gdb動態除錯,在0x080486d5出下斷點,檢視eax中存放的地址,可以看到是0xffffc1e8.
──────────────────────────────────────────────────[ REGISTERS ]────────────────────────────────────────────────── EAX 0xffffc1e8 ◂— 0xca0000 EBX 0x0 ECX 0x1 EDX 0xffffc1e8 ◂— 0xca0000 EDI 0xf7faf000 (_GLOBAL_OFFSET_TABLE_) ◂— 0x1b2db0 ESI 0x1 EBP 0xffffc258 ◂— 0x0 ESP 0xffffc1b0 —▸ 0xf7ffda7c —▸ 0xf7fd2b18 —▸ 0xf7ffd920 ◂— 0x0 EIP 0x80486d5 (main+261) ◂— 0x45830888
接下來我們檢視當程式執行結束後esp指向的地址即為返回地址:
.text:080488EE leave .text:080488EF lea esp, [ecx-4] .text:080488F2 retn .text:080488F2 ; } // starts at 80485D0 .text:080488F2 main endpret
在0x080488f2出下斷點,檢視暫存器esp中的值:
──────────────────────────────────────────────────[ REGISTERS ]────────────────────────────────────────────────── EAX 0x0 EBX 0x0 ECX 0xffffc270 ◂— 0x1 EDX 0xf7fb087c (_IO_stdfile_0_lock) ◂— 0x0 EDI 0xf7faf000 (_GLOBAL_OFFSET_TABLE_) ◂— 0x1b2db0 ESI 0x1 EBP 0x0 ESP 0xffffc26c —▸ 0xf7e14286 (__libc_start_main+246) ◂— add esp, 0x10 EIP 0x80488f2 (main+802) ◂— 0x669066c3
可以看到esp中的地址為0xffffc26c, 所以得到距離為:0xffffc26c-0xffffc1e8 = 0x84