Anti Flag
4 minutos de lectura
Se nos proporciona un binario llamado anti_flag
:
$ file anti_flag
anti_flag: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=b8de97bc12c627606510140e43fc13e2efffcee5, for GNU/Linux 3.2.0, stripped
Descompilación
Si lo abrimos en Ghidra, veremos esta función main
:
/* WARNING: Removing unreachable block (ram,0x00101525) */
undefined8 main(undefined8 param_1, undefined8 param_2, undefined8 param_3, undefined8 param_4, undefined8 param_5, undefined8 param_6) {
size_t sVar1;
long lVar2;
sVar1 = strlen(&DAT_00102011);
malloc(sVar1 << 2);
lVar2 = ptrace(PTRACE_TRACEME, 0, 1, 0, param_5, param_6, param_2);
if (lVar2 == -1) {
puts("Well done!!");
} else {
puts("No flag for you :(");
}
return 0;
}
Básicamente, está usando ptrace
para ver si el programa se ejecuta dentro de un depurador o no. Entonces tenemos dos comportamientos diferentes:
$ ./anti_flag
No flag for you :(
$ gdb -q anti_flag
Reading symbols from anti_flag...
(No debugging symbols found in anti_flag)
gef➤ run
Starting program: ./anti_flag
Well done!!
[Inferior 1 (process 2564048) exited normally]
Sin embargo, la flag no se muestra.
Análisis de código ensamblador
En Ghidra, hay una advertencia. De hecho, si analizamos el código de ensamblador, notaremos que hay un bloque de código inalcanzable:
$ objdump -M intel -d anti_flag
anti_flag: file format elf64-x86-64
...
Disassembly of section .text:
00000000000010e0 <.text>:
...
1486: f3 0f 1e fa endbr64
148a: 55 push rbp
148b: 48 89 e5 mov rbp,rsp
148e: 48 83 ec 30 sub rsp,0x30
1492: 89 7d dc mov DWORD PTR [rbp-0x24],edi
1495: 48 89 75 d0 mov QWORD PTR [rbp-0x30],rsi
1499: c7 45 e4 00 00 00 00 mov DWORD PTR [rbp-0x1c],0x0
14a0: 48 8d 05 5d 0b 00 00 lea rax,[rip+0xb5d] # 2004 <ptrace@plt+0xf34>
14a7: 48 89 45 e8 mov QWORD PTR [rbp-0x18],rax
14ab: 48 8d 05 5f 0b 00 00 lea rax,[rip+0xb5f] # 2011 <ptrace@plt+0xf41>
14b2: 48 89 45 f0 mov QWORD PTR [rbp-0x10],rax
14b6: 48 8b 45 f0 mov rax,QWORD PTR [rbp-0x10]
14ba: 48 89 c7 mov rdi,rax
14bd: e8 de fb ff ff call 10a0 <strlen@plt>
14c2: 48 c1 e0 02 shl rax,0x2
14c6: 48 89 c7 mov rdi,rax
14c9: e8 f2 fb ff ff call 10c0 <malloc@plt>
14ce: 48 89 45 f8 mov QWORD PTR [rbp-0x8],rax
14d2: b9 00 00 00 00 mov ecx,0x0
14d7: ba 01 00 00 00 mov edx,0x1
14dc: be 00 00 00 00 mov esi,0x0
14e1: bf 00 00 00 00 mov edi,0x0
14e6: b8 00 00 00 00 mov eax,0x0
14eb: e8 e0 fb ff ff call 10d0 <ptrace@plt>
14f0: 48 83 f8 ff cmp rax,0xffffffffffffffff
14f4: 75 13 jne 1509 <ptrace@plt+0x439>
14f6: 48 8d 3d 2e 0b 00 00 lea rdi,[rip+0xb2e] # 202b <ptrace@plt+0xf5b>
14fd: e8 8e fb ff ff call 1090 <puts@plt>
1502: b8 00 00 00 00 mov eax,0x0
1507: eb 44 jmp 154d <ptrace@plt+0x47d>
1509: 81 7d e4 39 05 00 00 cmp DWORD PTR [rbp-0x1c],0x539
1510: 74 13 je 1525 <ptrace@plt+0x455>
1512: 48 8d 3d 1e 0b 00 00 lea rdi,[rip+0xb1e] # 2037 <ptrace@plt+0xf67>
1519: e8 72 fb ff ff call 1090 <puts@plt>
151e: b8 00 00 00 00 mov eax,0x0
1523: eb 28 jmp 154d <ptrace@plt+0x47d>
1525: 48 8b 55 f8 mov rdx,QWORD PTR [rbp-0x8]
1529: 48 8b 4d f0 mov rcx,QWORD PTR [rbp-0x10]
152d: 48 8b 45 e8 mov rax,QWORD PTR [rbp-0x18]
1531: 48 89 ce mov rsi,rcx
1534: 48 89 c7 mov rdi,rax
1537: e8 c3 fe ff ff call 13ff <ptrace@plt+0x32f>
153c: 48 8b 45 f8 mov rax,QWORD PTR [rbp-0x8]
1540: 48 89 c7 mov rdi,rax
1543: e8 48 fb ff ff call 1090 <puts@plt>
1548: b8 00 00 00 00 mov eax,0x0
154d: c9 leave
154e: c3 ret
...
La llamada a ptrace
está en el offset 14eb
. Después de llamar a puts
, hay un salto a 154d
, que termina el programa. Sin embargo, hay instrucciones que nunca se ejecutan entre 1525
y 1548
.
También podemos notar que Ghidra encuentra funciones llamadas FUN_001013ff
, FUN_001011c9
, FUN_00101201
y FUN_001012de
. Ninguna de esas funciones se llama en la función main
descompilada, debido al salto incondicional.
Parcheo
Una forma de resolver este problema es cambiando jmp 154d
(e8 28
en código máquina) a nop; nop
(90 90
en código máquina), para que no haya salto incondicional:
$ xxd -p anti_flag | tr -d \\n | sed s/eb28/9090/g | xxd -r -p > anti_flag_patched
Flag
Ahora, si ejecutamos el binario parcheado, veremos la flag:
$ chmod +x anti_flag_patched
$ ./anti_flag_patched
No flag for you :(
HTB{y0u_trac3_m3_g00d!!!}