这关还是得突破程序的限制,去读出token的内容。flag13的代码如下:
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <string.h>
#define FAKEUID 1000
int main(int argc, char **argv, char **envp)
{
int c;
char token[256];
if(getuid() != FAKEUID) {
printf("Security failure detected. UID %d started us, we expect %d\n", getuid(), FAKEUID);
printf("The system administrators will be notified of this violation\n");
exit(EXIT_FAILURE);
}
// snip, sorry :)
printf("your token is %s\n", token);
}
主要注意if(getuid() != FAKEUID)
这句:通过getuid获得当前用户的uid与FAKEUID做比较,(FAKEUID是一个宏,值为1000,在代码第7行中定义),如果uid=1000的用户才可以读取token。这里我纳闷了一会儿,通过查阅,得到方法:
这儿需要涉及逆向工程的知识。一般函数的返回值存放在eax寄存器里的。getuid调用后,eax寄存器里就是当前用户的uid。直接修改eax的内容即可。
用level13登录系统,进入/home/flag13
level13@nebula:gdb flag13 #用gdb调试flag13
(gdb)disassemble main #反汇编main函数
看这:
0x080484ef <+43>:call0x80483c0 <getuid@plt>
0x080484f4 <+48>:cmp$0x3e8,%eax
这里就是判断语句了,在cmp $0x3e8,%eax这里下个断点:
break *0x080484f4
然后执行程序,程序会自动在断点处暂停运行。查看eax寄存器:
print $eax
$1 = 1014
我们当前用户的uid是1014。接着就是设置eax的值为1000了:
set $eax=1000
print $eax
$2 = 1000
最后让程序继续运行:
continue
显示出tokenyour token is b705702b-76a8-42b0-8844-3adabbe5ac58
这个token值就是flag13的密码,试着登录它:
level13@nebula:~$ su flag13
Password:
sh-4.2$ getflag
You have successfully executed getflag on a target account
sh-4.2$ (gdb)disassemble mainlevel13@nebula:gdb flag13