这是刚结束的ångstromCTF 2019的最后一道逆向题目,日常处理Windows逆向比较多,第一次遇到Linux的反调试,写个笔记记录一下做题过程。
拖入IDA分析,发现代码很明显被压缩或者加密; strings查看字符串发现UPX字样
看样子应该是被UPX加壳了,但是upx -d 并不能脱壳;类比Windows下UPX壳可能存在的一些操作,猜测可能是upx的一些壳特征被修改,导致不能正常脱壳。
但是,我不擅长Linux手动脱壳和ELFwen文件upx壳的修复,所尝试直接动态分析。gdb 加载直接运行,程序出现崩溃,猜测可能是存在反调试;程序单独运行,然后gdb,附加依然不成功:
看到应该存在ptrace反调试。google了一波ptrace反调试后,知道了大概原理,但是解题依然没有思路。
尝试从内存中dump运行起来的ELF文件。
内存中搜索可能存在的ELF文件
可以发现在0x00007ffff7ff2001处存在一个ELF文件此处内存通过mmap得到,猜测此处应该是UPX壳脱壳后的部分。
dump此处内存
gdb-peda$ dump binary memory 1.bin 0x00007ffff7ff2000 0x00007ffff7ffe000
将dump的内存载入IDA分析
可以大致看到程序执行流程,但是没有了got表
可以看到,在程序入口处有ptrace反调试,并且ptrace的调用是通过syscall实现的,不是通过调用库函数
flag检查
通过以上分析可知,如果可以在flag与内存内容对比的时候下断点,就可以从内存中直接获取到flag。那么接下来的问题就是bypass ptrace。
利用上述方法四,catch syscall ptrace,然后修改返回值rax的值;之后单步执行到flag校验处,从内存中获取flag即可,不再赘述。
平时调试Linux程序比较少,对Linux的反调试更不了解,通过着一道题目学到不少东西。
$Info: This file is packed with the UPX executable packer http://upx.sf.net $
$Id: UPX 3.95 Copyright (C) 1996-2018 the UPX Team. All Rights Reserved. $
upx: bugger: NotPackedException: not packed by UPX
Unpacked 0 files.
warning: process 3891 is already traced by process 3792
ptrace: Operation not permitted.
/home/pwn/3891: No such file or directory.
gdb-peda$ find ELF
Searching for 'ELF' in: None ranges
Found 27 results, display max 27 items:
libc : 0x7ffff79df001 (rex.RB)
libc : 0x7ffff7b7103f (rex.RB)
bugger : 0x7ffff7dc0001 --> 0x10102464c45
bugger : 0x7ffff7dc0111 --> 0x300010102464c45
ld-2.23.so : 0x7ffff7dc1001 (rex.RB)
ld-2.23.so : 0x7ffff7dc69a2 (rex.RB)
(省略了部分)
ld-2.23.so : 0x7ffff7de2bd7 (rex.RB)
ld-2.23.so : 0x7ffff7de38b1 (rex.RB)
[vdso] : 0x7ffff7ff0001 (rex.RB)
mapped : 0x7ffff7ff2001 --> 0x10102464c45
gdb-peda$ vmmap
Start End Perm Name
0x00007ffff79df000 0x00007ffff7b9f000 r-xp /lib/x86_64-linux-gnu/libc-2.23.so
0x00007ffff7b9f000 0x00007ffff7d9f000 ---p /lib/x86_64-linux-gnu/libc-2.23.so
0x00007ffff7d9f000 0x00007ffff7da3000 r--p /lib/x86_64-linux-gnu/libc-2.23.so
0x00007ffff7da3000 0x00007ffff7da5000 rw-p /lib/x86_64-linux-gnu/libc-2.23.so
0x00007ffff7da5000 0x00007ffff7da9000 rw-p mapped
0x00007ffff7dc0000 0x00007ffff7dc1000 r--p /home/pwn/Desktop/angstromctf/re/5/bugger
0x00007ffff7dc1000 0x00007ffff7de7000 r-xp /lib/x86_64-linux-gnu/ld-2.23.so
0x00007ffff7de7000 0x00007ffff7fe6000 ---p mapped
0x00007ffff7fe6000 0x00007ffff7fe7000 r--p /lib/x86_64-linux-gnu/ld-2.23.so
0x00007ffff7fe7000 0x00007ffff7fe8000 rw-p /lib/x86_64-linux-gnu/ld-2.23.so
0x00007ffff7fe8000 0x00007ffff7fe9000 rw-p mapped
0x00007ffff7fea000 0x00007ffff7fed000 rw-p mapped
0x00007ffff7fed000 0x00007ffff7ff0000 r--p [vvar]
0x00007ffff7ff0000 0x00007ffff7ff2000 r-xp [vdso]
0x00007ffff7ff2000 0x00007ffff7ff3000 r--p mapped
0x00007ffff7ff3000 0x00007ffff7ffc000 r-xp mapped
0x00007ffff7ffc000 0x00007ffff7ffe000 r--p mapped
0x00007ffff7ffe000 0x00007ffff8020000 rw-p [heap]
0x00007ffffffde000 0x00007ffffffff000 rw-p [stack]
0xffffffffff600000 0xffffffffff601000 r-xp [vsyscall]
sub_9503();
sub_1030(sub_96EF, 0LL);
sub_1080("Hey, dude! Please enter the flag: ");
sub_10A0(&v5, 500LL, qword_C380);
if ( (unsigned int)sub_956F(&v5) )
{
v0 = "Cool.";
sub_1050("Cool.");
}
else
{
v0 = "Idiot.";
sub_1050("Idiot.");
}
LOAD:0000000000009503 sub_9503 proc near ; CODE XREF: sub_9812+1F↓p
LOAD:0000000000009503 push rbp
LOAD:0000000000009504 mov rbp, rsp
LOAD:0000000000009507 mov eax, 65h ; 'e'
LOAD:000000000000950C mov edi, 0 ; request
LOAD:0000000000009511 mov esi, 0 ; pid
LOAD:0000000000009516 mov edx, 0 ; addr
LOAD:000000000000951B syscall ; LINUX - sys_ptrace
;检查ptrace返回值
LOAD:000000000000951D test eax, eax
LOAD:000000000000951F jz short loc_953A
LOAD:0000000000009521 lea rdi, aNoDebuggersIdi ; "No debuggers. Idiot."
LOAD:0000000000009528 call sub_1050
;ptrace检测到调试后向0地址写入数据,从而导致异常
LOAD:000000000000952D mov eax, 0
LOAD:0000000000009532 mov dword ptr [rax], 0
;OAD:0000000000009538 jmp short loc_956C
LOAD:000000000000953A ; ---------------------------------------------------------------------------
LOAD:000000000000953A
LOAD:000000000000953A loc_953A: ; CODE XREF: sub_9503+1C↑j
LOAD:000000000000953A mov eax, 65h ; 'e'
LOAD:000000000000953F mov edi, 0 ; request
LOAD:0000000000009544 mov esi, 0 ; pid
LOAD:0000000000009549 mov edx, 0 ; addr
LOAD:000000000000954E syscall ; LINUX - sys_ptrace
LOAD:0000000000009550 cmp eax, 0FFFFFFFFh
LOAD:0000000000009553 jz short loc_956C
LOAD:0000000000009555 lea rdi, aStillNoDebugge ; "Still no debuggers. Idiot."
LOAD:000000000000955C call sub_1050
;ptrace检测到调试后向0地址写入数据,从而导致异常
LOAD:0000000000009561 mov eax, 0
LOAD:0000000000009566 mov dword ptr [rax], 1
LOAD:000000000000956C
LOAD:000000000000956C loc_956C: ; CODE XREF: sub_9503+35↑j
LOAD:000000000000956C ; sub_9503+50↑j
LOAD:000000000000956C nop
LOAD:000000000000956D pop rbp
LOAD:000000000000956E retn
LOAD:000000000000956E sub_9503 endp
//虽然没有got表,但是可以猜测此处是读取文件
v1 = sub_10F0((__int64)"/proc/self/exe", (__int64)"rb");
sub_10E0(v1, 0LL, 2LL);
v2 = sub_10C0(v1);
sub_10E0(v1, 0LL, 0LL);
sub_1060(v1);
v10 = 1;
v3 = v2 - 1639;
v4 = (char *)qword_CD68;
//对读取到的文件内容进行处理
sub_8DF9(qword_CD68, v2 - 1639, v13, 64LL);
sub_1535(v4, v2 - 1639);
for ( i = 0; i <= 63; ++i )
{
//检查flag开头是否为"actf{not_an_idiot._"
if ( (unsigned int)sub_1090("actf{not_an_idiot._", v9, 19LL) )
LOBYTE(v10) = 0;
//检查flag是否以'}'结尾
if ( asc_A119[0] != *(_BYTE *)(v9 + 147) )
LOBYTE(v10) = 0;
//flag内容与处理后的文件内容进行对比
sub_1100(&v12, "%02x", (unsigned __int8)v13[i]);
v3 = 2 * i + 19LL + v9;
v4 = &v12;
if ( (unsigned int)sub_1090(&v12, v3, 2LL) )
v10 = 0;
else
v10 &= 1u;
}
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
最后于 2019-6-21 11:53
被QuietBar编辑
,原因:
上传的附件: