本人是新学pwn的一个小菜鸟,最近在边学习边做pwnable.kr网站中的习题.现将一些菜鸟的解题方法与心得整理如下,欢迎各位大佬批评指正,谢谢!!!
本文环境:
- Windows11家庭中文版,版本21H2(OS 内部版本 22000.978)
- WSL 2
- Ubuntu-18.04.05 LTS
1. Toddler's Bottle
1.1 fd
第一题是一道关于Linux系统中的文件描述符(File Descriptor)的比较简单的题目.
预备知识: 文件描述符是系统用于唯一标识文件的一串无符号整型数字,它们由小到大依次分配.其中,每个进程开始时都会有三个打开的文件,为:标准输入(描述符0),标准输出(描述符1),标准错误(描述符2).在<unistd.h>中定义了成了常量STDIN_FILENO
,STDOUT_FILENO
和STDERR_FILENO
.
首先我们使用题目给的命令进入远程服务器,括号内的guest
为登录密码(注:输入密码时不可见):
ssh fd@pwnable.kr -p2222
# ssh(Secure Shell)是登录远程服务器的命令
# 其中,fd@pwnable.kr表示远程服务器的域名,-p2222表示端口(port)2222
# 使用exit命令退出连接
# 相关参数及用法可参考https://cloud.tencent.com/developer/article/1594881
之后我们就得到这样的界面
使用命令ls
查看目录下文件或使用ls -la
查看目录下文件以及相关权限
我们发现目标文件fd
,fd.c
和flag
.但是在这个过程中,我们发现该服务器访问较慢,于是使用如下命令下载本地.但在此之前,为了方便管理,可先使用命令mkdir namefile
创建以namefile
为名文件夹,再进入该文件夹,将文件下载到该文件夹下:
mkdir fd
# 本文创建文件夹名为fd
cd fd
# 进入fd文件夹中
scp -P2222 fd@pwnable.kr:fd .
scp -P2222 fd@pwnable.kr:fd.c .
# scp(Secure Copy)用于复制文件和目录
# 其中,fd@pwnable.kr表示远程服务器的域名,-P2222表示端口2222(注意是大写P),
# .表示本地当前目录
# 相关参数及用法可参考https://www.runoob.com/linux/linux-comm-scp.html
随后我们可以使用vim
命令查看fd.c
的内容(注释为本人后加之):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char buf[32];
// argc表示文件参数的的个数,argv表示文件参数的地址,envp表示环境变量
int main(int argc, char* argv[], char* envp[]){
// 判断是否有参数,在命令行,可执行文件的文件名本身算作一个参数,其地址为argv[0],所以argc始终大于等于1
if(argc<2){
printf("pass argv[1] a number\n");
return 0;
}
// atoi()为标准库函数,位于<stdlib.h>
// 它将参数所指的字符串转化成int整型
// 可参考: https://www.runoob.com/cprogramming/c-function-atoi.html
int fd = atoi( argv[1] ) - 0x1234;
int len = 0;
// read()函数为系统调用函数,它从文件描述符为fd的拷贝32个字符到buf中
// 返回值为真正拷贝的字符的个数.这是EOF的存在导致的,因为它可能没有那么多的字符供拷贝
// 可参考: https://blog.csdn.net/zjhkobe/article/details/6633446
len = read(fd, buf, 32);
// strcmp用于比较两个字符的大小,如果两字符相等,则返回0
if(!strcmp("LETMEWIN\n", buf)){
printf("good job :)\n");
system("/bin/cat flag");
exit(0);
}
printf("learn about Linux file IO\n");
return 0;
}
由上述代码及注释可知,本题需要传递一个合适参数,使得fd标识的文件中的32位字符为LETMEWIN\n
.根据预备知识可知,我们可以使用fd=0的标准输入,来输入所需的字符.我们的输入值应为十进制,0x1234
的十进制为4660
.如下图所示: