#scp命令
这次利用 scp命令直接下载了文件。
scp命令学习
具体命令
要确保 我们本地的文件夹是可以操作的,不然会报权限问题 ls-l 可以查看目录下的文件和文件夹的权限 给权限可以用 chmod -R 777 路径/文件(夹)名
命令:scp -r -P 2222 【题目名字】@pwnable.kr:/home/【题目名字】/* /home/linhua/pwn
scp -r -P 2222 input2@pwnable.kr:/home/input2/* /home/linhua/pwn
我们用ssh连接试下
发现除了flag文件,另外两个都会下载出来。不过也是哈,如果flag都被拉出来了,还解啥题
知识点
fread
函数原型
size_t fread ( void buffer, size_t size, size_t count, FILE stream) ;
参 数
buffer
用于接收数据的内存地址
size
要读的每个数据项的字节数,单位是字节
count
要读count个数据项,每个数据项size个字节.
stream
输入流
返回值
返回真实读取的项数,若大于count则意味着产生了错误。另外,产生错误后,文件位置指示器是无法确定的。若其他stream或buffer为空指针,或在unicode模式中写入的字节数为奇数,此函数设置errno为EINVAL以及返回0.
##argv
argv['A'] = "\x00";
argv['B'] = "\x20\x0a\x0d";
argv['C'] ="55555";
这里可以用’A’作为参数的索引,这是原来没有见过的,默认把字符转换成ASCII码了。
1 |
|
这题需要的知识点很多
总共是五个关卡,每完成一个才能下一个
题目是为了让解题者满足代码中所需要满足的条件,总共5个,分别包括:参数传递、标准输入输出、环境变量、文件读写以及网络通信方面。
1.argv
参数第’A’和’B’位分别为”\x00”和”\x20\x0a\x0d”,也就是第65位和第66位(第0位为可执行文件的路径),但是’\x00’会截断。
于是使用execve运行input文件,execve函数在unistd(unix standard)头文件中:
int execve(const char path, char const argv[], char *const envp[]);
以argv参数进行传递相应参数。
2.stdio
ssize_t read(int fildes, void *buf, size_t nbytes);
摘自 http://codewiki.wikidot.com/c:system-calls:read
Field Description
int fildes The file descriptor of where to read the input. You can either use a file descriptor obtained from the open system call, or you can use 0, 1, or 2, to refer to standard input, standard output, or standard error, respectively.
const void *buf A character array where the read content will be stored.
size_t nbytes The number of bytes to read before truncating the data. If the data to be read is smaller than nbytes, all data is saved in the buffer.
return value Returns the number of bytes that were read. If value is negative, then the system call returned an error.
可以看到分别需要从stdin和stderr读取相关的数据,但是stderr没法写,于是需要用到c中的叫做管道(pipe)的东西可用于子进程与父进程之间的通讯使用;于是子进程向缓冲区写数据,而父进程先将定义的相应缓冲区分别替换stdin和stderr,之后则可以从缓冲区进行读取。
3.env
getenv函数获取系统中环境变量,这个同样以execve进行处理,其中的envp参数进行传递。
4.file
常规操作,自己创建一个文件,然后写”\x00\x00\x00\x00”进去然后再读即可。
5.network
是以传递的第C个参数作为监听端口,以及socket通信获取传来的消息,采用本地通信。socket网络编程网上一搜就出来的,其实百度百科说的还挺清楚的…中间需要sleep几秒等待接收信息的服务开启,然后传递信息。
最后在/tmp目录下面可以创建一个文件xxx,但是由于后面还得创建一个与/home/input2/flag的软链接(因为在/tmp目录下仍然没有权限cat flag),因为在运行input2文件时路径还是相对路径:
ln -s /home/input2/flag flag
之后创建一个c文件编译运行即可。
看大佬 题解:
题解
原文
这里首先先明确:就是我们很明显这个输入是个很复杂的东西,我们无法在命令行里直接输入参数,当然也可以通过写exp。
这里我用的是execve函数,其原型如下
int
execve(const char path, char const argv[], char *const envp[]);
所以我们通过execve函数来给源文件input传值
这里我们需要查看一下input文件的位置
-al查看全部文件
可以得知我们的path为”/home/input2/input”
然后接下来一个问题就是,我们将把我们这个写的文件放在服务器的哪里呢?这个服务器对我们的权限做了很大的限制。我在服务器上没有找到能够创建文件的地方,所以我想到的办法是通过scp将原文件都下载到本地,然后再本地上做~(注意,如果下载到本地的话,这个path就会有变化,这里我就暂且先不做更改)
所以我们这个文件暂且命名为input_replace.c1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
int main(int argc, char const *argv[])
{
char **new_agrv;
char **new_envp;
//argv
//stdio
//env
//file
//network
execve("/home/input2/input",new_argv,new_envp);
return 0;
}
然后我们就来逐个击破吧~
一步步来把
part1
1 | if(argc != 100) return 0; |
我们推断程序必须在以下条件下执行:
1.正好100个参数
2.第65个参数(A的ascii值为65)必须是空字符串
3.第66个参数66(B的ascii值为66)必须是\ x20 \ x0a \ x0d
这里也就是让我们在命令行参数输入100个参数,由于我们的输入运行程序占一个,所以我们也就输入99个参数就可以了。(请注意,我们总共添加了99个参数,因为程序的名称计为一个。)但是这里我们要注意一下,因为我们是通过input_replace.c来调用input,所以我们的第一个参数是./input_replace,比直接运行input多了这么一个参数,所以实际上我们需要的是101个参数。
part1的代码就好了1
2
3
4
5
6
7
8char * new_argv[101];
for(int i = 0;i<100;i++)
{
new_argv[i] = "";
}
new_argv['A'] = "\x00";
new_argv['B'] = "\x20\x0a\x0d";
new_argv[100] = NULL;
原文:https://blog.csdn.net/qq_37414405/article/details/84991438