Меня попросили взломать программу на собеседовании

Original author: Eren Yağdıran
  • Translation
TL;DR Меня попросили взломать программу на собеседовании. И я получил работу.

Всем привет,

Я собеседовался на позицию инженера программной безопасности, они спрашивали в основном разные низкоуровневые вещи. Некоторые ответы я знал, некоторые нет.
Потом они прислали email с защищённым и зашифрованным бинарником, который нужно было взломать.
Когда я добрался до дома, я скачал его и увидел, что он спрашивает пароль. Они хотели, чтобы я нашёл этот пароль.
Вот что я увидел при первом запуске:

root@lisa:~# ./CrackTheDoor

*** DOOR CONTROL SYSTEM ***

PASSWORD:

Я напечатал три раза какие-то глупые слова, и программа закрылась.
У меня ещё есть инструменты в запасе для анализа. Давайте соберём побольше информации о файле.

root@lisa:~# file CrackTheDoor
CrackTheDoor: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.15, BuildID[sha1]=0x9927be2fe310bea01d412164103b9c8b2d7567ea, not stripped
root@lisa:~#

Окей, теперь мы знаем немного больше о бинарнике.

root@lisa:~# ldd CrackTheDoor
linux-gate.so.1 => (0xf777b000)
libc.so.6 => /lib32/libc.so.6 (0xf760c000)
/lib/ld-linux.so.2 (0xf777c000)
root@lisa:~#

Ничего необычного. Объясню немного. linux-gate.so вы можете не найти в своей файловой системе. Но ldd показывает его как общую библиотеку. Это Virtual DSO.

Итак, вы знаете о linux-gate.so.1.
Возможно вы также знаете, что libc.so.6 это основная C библиотека для GNU систем.
ld-linux.so это загрузчик динамических библиотек в linux.

Запустим программу в отладчике и посмотрим что произойдёт.

root@lisa:~# gdb CrackTheDoor
GNU gdb (GDB) 7.4.1-debian
Copyright © 2012 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type «show copying»
and «show warranty» for details.
This GDB was configured as «x86_64-linux-gnu».
For bug reporting instructions, please see:
<www.gnu.org/software/gdb/bugs>…
Reading symbols from /root/CrackTheDoor...(no debugging symbols found)...done.
(gdb) r
Starting program: /root/CrackTheDoor

Program received signal SIGSEGV, Segmentation fault.
0x080484fb in __do_global_dtors_aux ()
(gdb)

Программа упала. Это значит, что в ней должны быть какие-то антиотладочные трюки. Окей…

Запустим её снова и посмотрим точку входа программы.

root@lisa:~# gdb CrackTheDoor
GNU gdb (GDB) 7.4.1-debian
Copyright © 2012 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type «show copying»
and «show warranty» for details.
This GDB was configured as «x86_64-linux-gnu».
For bug reporting instructions, please see:
<www.gnu.org/software/gdb/bugs>…
Reading symbols from /root/CrackTheDoor...(no debugging symbols found)...done.
(gdb) info file
Symbols from "/root/CrackTheDoor".
Local exec file:
`/root/CrackTheDoor', file type elf32-i386.
Entry point: 0x804762c

...

Поставим breakpoint на точку входа и начнём отладку:

b * 0x804762c


Затем нажмём «r» для запуска. Окажемся на первой строке точки входа программы:

gdb) x/30i $pc
=> 0x804762c: pusha
0x804762d: mov $0xaa,%dl
0x804762f: mov $0x8048480,%edi
0x8047634: mov $0x8048cbc,%ecx
0x8047639: mov %edi,0x80476f3
0x804763f: mov %ecx,0x80476f7
0x8047645: sub %edi,%ecx
0x8047647: mov $0x804762f,%esi
0x804764c: push $0x80476c1
0x8047651: pusha
0x8047652: mov $0x55,%al
0x8047654: xor $0x99,%al
0x8047656: mov $0x8047656,%edi
0x804765b: mov $0x80476e5,%ecx
0x8047660: sub $0x8047656,%ecx
0x8047666: repnz scas %es:(%edi),%al
0x8047668: je 0x804770a
0x804766e: mov %edi,0x80476eb
0x8047674: popa
0x8047675: add 0x80476eb,%edx
0x804767b: ret

Должно выглядеть как-то так. Можно выбрать синтаксис между AT&T и Intel версиями. Мне больше нравится Intel.

По адресу 0x8047654, мы присваиваем 0x55 al регистру, а затем XOR'им его с 0x99 получая 0xCC.
0xCC это очень важно, так как это означает остановку процесса. Когда отладчик хочет прервать выполнение программы, он заменяет байты на 0xCC в том месте, где хочет её остановить.
По адресу 0x8047666, мы видим repnz scas; это означает поиск участка памяти, ограниченного es и edi, на предмет значения в al(0xCC).
Итак, эти строчки просто сканируют память, и если там есть 0xCC, программа прекращает выполнение.
Не хочу тратить слишком много времени тут. Запустим strace:

root@lisa:~# strace ./CrackTheDoor
execve("./CrackTheDoor", ["./CrackTheDoor"], [/* 17 vars */]) = 0
[ Process PID=31085 runs in 32 bit mode. ]
brk(0) = 0x9972000
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xfffffffff7715000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=35597, ...}) = 0
mmap2(NULL, 35597, PROT_READ, MAP_PRIVATE, 3, 0) = 0xfffffffff770c000
close(3) = 0
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
open("/lib32/libc.so.6", O_RDONLY) = 3
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\300o\1\0004\0\0\0"..., 512) = 512
fstat64(3, {st_mode=S_IFREG|0755, st_size=1441884, ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xfffffffff770b000
mmap2(NULL, 1456504, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xfffffffff75a7000
mprotect(0xf7704000, 4096, PROT_NONE) = 0
mmap2(0xf7705000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x15d) = 0xfffffffff7705000
mmap2(0xf7708000, 10616, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xfffffffff7708000
close(3) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xfffffffff75a6000
set_thread_area(0xffe4d864) = 0
mprotect(0xf7705000, 8192, PROT_READ) = 0
mprotect(0x8049000, 4096, PROT_READ) = 0
mprotect(0xf7733000, 4096, PROT_READ) = 0
munmap(0xf770c000, 35597) = 0
ptrace(PTRACE_TRACEME, 0, 0x1, 0) = -1 EPERM (Operation not permitted)
ptrace(PTRACE_TRACEME, 0, 0x1, 0) = -1 EPERM (Operation not permitted)

Судя по последним двум строчкам, программа упала опять. Из-за системного вызова ptrace.

Ptrace — это аббревиатура для «Process Trace». При помощи ptrace вы можете контролировать другой процесс меняя его состояние, как это делают отладчики.

Отладчики очень интенсивно используют ptrace. Это их работа.

Код для такого участка может выглядеть примерно так:

int main()
{
    if (ptrace(PTRACE_TRACEME, 0, 1, 0) < 0) {
        printf("DEBUGGING... Bye\n");
        return 1;
    }
    printf("Hello\n");
    return 0;
}

Кстати, вы можете сделать ptrace[PTRACE_TRACEMe] только один раз, так что если отладчик вызвал ptrace на нашей программе до этого, то наш вызов вернёт false и мы поймём, что кто-то контролирует программу извне.
Нам нужно обойти защиту на ptrace чтобы программа не думала, что мы пытаемся её отлаживать.
Мы заменим результат системного вызова.
Мы будем определять когда программа вызывает ptrace и возвращать ноль.
В домашней папке я создал новый .gdbinit файл. Следовательно, каждый раз когда я запускаю gdb, конфигурация будет загружаться автоматически.

~/.gdbinit
set disassembly-flavor intel # Intel syntax is better
set disassemble-next-line on
catch syscall ptrace #Catch the syscall.
commands 1
set ($eax) = 0
continue
end

В eax будет результат системного вызова. И он всегда будет 0, что означает истину в нашем случае.

Таким образом мы обошли защиту от отладки и можем вернуться к gdb.
eren@lisa:~$ gdb ./CrackTheDoor
GNU gdb (GDB) 7.4.1-debian
Copyright © 2012 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type «show copying»
and «show warranty» for details.
This GDB was configured as «x86_64-linux-gnu».
For bug reporting instructions, please see:
<www.gnu.org/software/gdb/bugs>…
Catchpoint 1 (syscall 'ptrace' [26])
Reading symbols from /home/eren/CrackTheDoor...(no debugging symbols found)...done.
(gdb) r
Starting program: /home/eren/CrackTheDoor

Catchpoint 1 (call to syscall ptrace), 0x08047698 in ?? ()
=> 0x08047698: 3d 00 f0 ff ff cmp eax,0xfffff000

Catchpoint 1 (returned from syscall ptrace), 0x08047698 in ?? ()
=> 0x08047698: 3d 00 f0 ff ff cmp eax,0xfffff000

*** DOOR CONTROL SYSTEM ***

PASSWORD:

Я поставил breakpoint на PJeGPC4TIVaKFmmy53DJ

<code>Breakpoint 2, 0x08048534 in PJeGPC4TIVaKFmmy53DJ ()
=> 0x08048534 <PJeGPC4TIVaKFmmy53DJ+0>: 1e  push   ds
(gdb) x/40i $pc
=> 0x8048534 <PJeGPC4TIVaKFmmy53DJ>:    push   ds
   0x8048535 <PJeGPC4TIVaKFmmy53DJ+1>:    mov    ebp,esp
   0x8048537 <PJeGPC4TIVaKFmmy53DJ+3>:    sub    esp,0x20
   0x804853a <PJeGPC4TIVaKFmmy53DJ+6>:    mov    BYTE PTR [ebp-0x1],0xe4
   0x804853e <PJeGPC4TIVaKFmmy53DJ+10>:   mov    BYTE PTR [ebp-0x2],0x87
   0x8048542 <PJeGPC4TIVaKFmmy53DJ+14>:   mov    BYTE PTR [ebp-0x3],0xfb
   0x8048546 <PJeGPC4TIVaKFmmy53DJ+18>:   mov    BYTE PTR [ebp-0x4],0xbe
   0x804854a <PJeGPC4TIVaKFmmy53DJ+22>:   mov    BYTE PTR [ebp-0x5],0xc9
   0x804854e <PJeGPC4TIVaKFmmy53DJ+26>:   mov    BYTE PTR [ebp-0x6],0x93
   0x8048552 <PJeGPC4TIVaKFmmy53DJ+30>:   mov    BYTE PTR [ebp-0x7],0x84
   0x8048556 <PJeGPC4TIVaKFmmy53DJ+34>:   mov    BYTE PTR [ebp-0x8],0xfc
   0x804855a <PJeGPC4TIVaKFmmy53DJ+38>:   mov    BYTE PTR [ebp-0x9],0x8d
   0x804855e <PJeGPC4TIVaKFmmy53DJ+42>:   mov    BYTE PTR [ebp-0xa],0xe5
   0x8048562 <PJeGPC4TIVaKFmmy53DJ+46>:   mov    BYTE PTR [ebp-0xb],0xbf
   0x8048566 <PJeGPC4TIVaKFmmy53DJ+50>:   mov    BYTE PTR [ebp-0xc],0x5c
   0x804856a <PJeGPC4TIVaKFmmy53DJ+54>:   mov    BYTE PTR [ebp-0xd],0xe2
   0x804856e <PJeGPC4TIVaKFmmy53DJ+58>:   mov    BYTE PTR [ebp-0xe],0x76
   0x8048572 <PJeGPC4TIVaKFmmy53DJ+62>:   mov    BYTE PTR [ebp-0xf],0x21
   0x8048576 <PJeGPC4TIVaKFmmy53DJ+66>:   mov    BYTE PTR [ebp-0x10],0xb8
   0x804857a <PJeGPC4TIVaKFmmy53DJ+70>:   mov    DWORD PTR [ebp-0x14],0x0
   0x8048581 <PJeGPC4TIVaKFmmy53DJ+77>:   mov    eax,DWORD PTR [ebp-0x14]
   0x8048584 <PJeGPC4TIVaKFmmy53DJ+80>:   add    eax,DWORD PTR [ebp+0x8]
   0x8048587 <PJeGPC4TIVaKFmmy53DJ+83>:   movzx  eax,BYTE PTR [eax]
   0x804858a <PJeGPC4TIVaKFmmy53DJ+86>:   test   al,al
   0x804858c <PJeGPC4TIVaKFmmy53DJ+88>:   je     0x8048808 <PJeGPC4TIVaKFmmy53DJ+724>
   0x8048592 <PJeGPC4TIVaKFmmy53DJ+94>:   mov    eax,DWORD PTR [ebp-0x14]
   0x8048595 <PJeGPC4TIVaKFmmy53DJ+97>:   add    eax,DWORD PTR [ebp+0x8]
   0x8048598 <PJeGPC4TIVaKFmmy53DJ+100>:  mov    edx,DWORD PTR [ebp-0x14]
   0x804859b <PJeGPC4TIVaKFmmy53DJ+103>:  add    edx,DWORD PTR [ebp+0x8]
   0x804859e <PJeGPC4TIVaKFmmy53DJ+106>:  movzx  edx,BYTE PTR [edx]
   0x80485a1 <PJeGPC4TIVaKFmmy53DJ+109>:  xor    dl,BYTE PTR [ebp-0x1]
   0x80485a4 <PJeGPC4TIVaKFmmy53DJ+112>:  mov    BYTE PTR [eax],dl
   0x80485a6 <PJeGPC4TIVaKFmmy53DJ+114>:  add    DWORD PTR [ebp-0x14],0x1
   0x80485aa <PJeGPC4TIVaKFmmy53DJ+118>:  mov    eax,DWORD PTR [ebp-0x14]
   0x80485ad <PJeGPC4TIVaKFmmy53DJ+121>:  add    eax,DWORD PTR [ebp+0x8]
   0x80485b0 <PJeGPC4TIVaKFmmy53DJ+124>:  movzx  eax,BYTE PTR [eax]
   0x80485b3 <PJeGPC4TIVaKFmmy53DJ+127>:  test   al,al
   0x80485b5 <PJeGPC4TIVaKFmmy53DJ+129>:  je     0x804880b <PJeGPC4TIVaKFmmy53DJ+727>
   0x80485bb <PJeGPC4TIVaKFmmy53DJ+135>:  mov    eax,DWORD PTR [ebp-0x14]
   0x80485be <PJeGPC4TIVaKFmmy53DJ+138>:  add    eax,DWORD PTR [ebp+0x8]
   0x80485c1 <PJeGPC4TIVaKFmmy53DJ+141>:  mov    edx,DWORD PTR [ebp-0x14]
   0x80485c4 <PJeGPC4TIVaKFmmy53DJ+144>:  add    edx,DWORD PTR [ebp+0x8]
   0x80485c7 <PJeGPC4TIVaKFmmy53DJ+147>:  movzx  edx,BYTE PTR [edx]
   0x80485ca <PJeGPC4TIVaKFmmy53DJ+150>:  xor    dl,BYTE PTR [ebp-0x2]</code>

Эта часть интересна. Я вижу манипулирование константами и то, что к подающимся данным на вход применяется XOR констант. Продолжим…

(gdb) x/30i X1bdrhN8Yk9NZ59Vb7P2
   0x8048838 <X1bdrhN8Yk9NZ59Vb7P2>:  sbb    ecx,DWORD PTR [ecx+0x20ec83e5]
   0x804883e <X1bdrhN8Yk9NZ59Vb7P2+6>:    mov    DWORD PTR [ebp-0x18],0x0
   0x8048845 <X1bdrhN8Yk9NZ59Vb7P2+13>:   mov    BYTE PTR [ebp-0x1],0xd9
   0x8048849 <X1bdrhN8Yk9NZ59Vb7P2+17>:   mov    BYTE PTR [ebp-0x2],0xcd
   0x804884d <X1bdrhN8Yk9NZ59Vb7P2+21>:   mov    BYTE PTR [ebp-0x3],0xc9
   0x8048851 <X1bdrhN8Yk9NZ59Vb7P2+25>:   mov    BYTE PTR [ebp-0x4],0xe5
   0x8048855 <X1bdrhN8Yk9NZ59Vb7P2+29>:   mov    BYTE PTR [ebp-0x5],0x9e
   0x8048859 <X1bdrhN8Yk9NZ59Vb7P2+33>:   mov    BYTE PTR [ebp-0x6],0xd0
   0x804885d <X1bdrhN8Yk9NZ59Vb7P2+37>:   mov    BYTE PTR [ebp-0x7],0xe8
   0x8048861 <X1bdrhN8Yk9NZ59Vb7P2+41>:   mov    BYTE PTR [ebp-0x8],0xa5
   0x8048865 <X1bdrhN8Yk9NZ59Vb7P2+45>:   mov    BYTE PTR [ebp-0x9],0xaf
   0x8048869 <X1bdrhN8Yk9NZ59Vb7P2+49>:   mov    BYTE PTR [ebp-0xa],0x87
   0x804886d <X1bdrhN8Yk9NZ59Vb7P2+53>:   mov    BYTE PTR [ebp-0xb],0xd2
   0x8048871 <X1bdrhN8Yk9NZ59Vb7P2+57>:   mov    BYTE PTR [ebp-0xc],0x79
   0x8048875 <X1bdrhN8Yk9NZ59Vb7P2+61>:   mov    BYTE PTR [ebp-0xd],0xa9
   0x8048879 <X1bdrhN8Yk9NZ59Vb7P2+65>:   mov    BYTE PTR [ebp-0xe],0x5d
   0x804887d <X1bdrhN8Yk9NZ59Vb7P2+69>:   mov    BYTE PTR [ebp-0xf],0x7
   0x8048881 <X1bdrhN8Yk9NZ59Vb7P2+73>:   mov    BYTE PTR [ebp-0x10],0x81
   0x8048885 <X1bdrhN8Yk9NZ59Vb7P2+77>:   mov    DWORD PTR [ebp-0x14],0x0
   0x804888c <X1bdrhN8Yk9NZ59Vb7P2+84>:   mov    eax,DWORD PTR [ebp-0x14]
   0x804888f <X1bdrhN8Yk9NZ59Vb7P2+87>:   add    eax,DWORD PTR [ebp+0x8]
   0x8048892 <X1bdrhN8Yk9NZ59Vb7P2+90>:   movzx  eax,BYTE PTR [eax]
   0x8048895 <X1bdrhN8Yk9NZ59Vb7P2+93>:   cmp    al,BYTE PTR [ebp-0x1]
   0x8048898 <X1bdrhN8Yk9NZ59Vb7P2+96>:   je     0x80488a2 <X1bdrhN8Yk9NZ59Vb7P2+106>
   0x804889a <X1bdrhN8Yk9NZ59Vb7P2+98>:   mov    eax,DWORD PTR [ebp-0x18]

Ещё константы…

И оставшаяся часть функции:

0x804889d <X1bdrhN8Yk9NZ59Vb7P2+101>:    jmp    0x8048a20 <X1bdrhN8Yk9NZ59Vb7P2+488>
   0x80488a2 <X1bdrhN8Yk9NZ59Vb7P2+106>:  add    DWORD PTR [ebp-0x14],0x1
   0x80488a6 <X1bdrhN8Yk9NZ59Vb7P2+110>:  mov    eax,DWORD PTR [ebp-0x14]
   0x80488a9 <X1bdrhN8Yk9NZ59Vb7P2+113>:  add    eax,DWORD PTR [ebp+0x8]
   0x80488ac <X1bdrhN8Yk9NZ59Vb7P2+116>:  movzx  eax,BYTE PTR [eax]
   0x80488af <X1bdrhN8Yk9NZ59Vb7P2+119>:  cmp    al,BYTE PTR [ebp-0x2]
   0x80488b2 <X1bdrhN8Yk9NZ59Vb7P2+122>:  je     0x80488bc <X1bdrhN8Yk9NZ59Vb7P2+132>
   0x80488b4 <X1bdrhN8Yk9NZ59Vb7P2+124>:  mov    eax,DWORD PTR [ebp-0x18]
   0x80488b7 <X1bdrhN8Yk9NZ59Vb7P2+127>:  jmp    0x8048a20 <X1bdrhN8Yk9NZ59Vb7P2+488>
   0x80488bc <X1bdrhN8Yk9NZ59Vb7P2+132>:  add    DWORD PTR [ebp-0x14],0x1
   0x80488c0 <X1bdrhN8Yk9NZ59Vb7P2+136>:  mov    eax,DWORD PTR [ebp-0x14]
   0x80488c3 <X1bdrhN8Yk9NZ59Vb7P2+139>:  add    eax,DWORD PTR [ebp+0x8]
   0x80488c6 <X1bdrhN8Yk9NZ59Vb7P2+142>:  movzx  eax,BYTE PTR [eax]
   0x80488c9 <X1bdrhN8Yk9NZ59Vb7P2+145>:  cmp    al,BYTE PTR [ebp-0x3]
   0x80488cc <X1bdrhN8Yk9NZ59Vb7P2+148>:  je     0x80488d6 <X1bdrhN8Yk9NZ59Vb7P2+158>
   0x80488ce <X1bdrhN8Yk9NZ59Vb7P2+150>:  mov    eax,DWORD PTR [ebp-0x18]
   0x80488d1 <X1bdrhN8Yk9NZ59Vb7P2+153>:  jmp    0x8048a20 <X1bdrhN8Yk9NZ59Vb7P2+488>
   0x80488d6 <X1bdrhN8Yk9NZ59Vb7P2+158>:  add    DWORD PTR [ebp-0x14],0x1
   0x80488da <X1bdrhN8Yk9NZ59Vb7P2+162>:  mov    eax,DWORD PTR [ebp-0x14]
   0x80488dd <X1bdrhN8Yk9NZ59Vb7P2+165>:  add    eax,DWORD PTR [ebp+0x8]
---Type <return> to continue, or q <return> to quit---
   0x80488e0 <X1bdrhN8Yk9NZ59Vb7P2+168>:  movzx  eax,BYTE PTR [eax]
   0x80488e3 <X1bdrhN8Yk9NZ59Vb7P2+171>:  cmp    al,BYTE PTR [ebp-0x4]
   0x80488e6 <X1bdrhN8Yk9NZ59Vb7P2+174>:  je     0x80488f0 <X1bdrhN8Yk9NZ59Vb7P2+184>
   0x80488e8 <X1bdrhN8Yk9NZ59Vb7P2+176>:  mov    eax,DWORD PTR [ebp-0x18]
   0x80488eb <X1bdrhN8Yk9NZ59Vb7P2+179>:  jmp    0x8048a20 <X1bdrhN8Yk9NZ59Vb7P2+488>
   0x80488f0 <X1bdrhN8Yk9NZ59Vb7P2+184>:  add    DWORD PTR [ebp-0x14],0x1
   0x80488f4 <X1bdrhN8Yk9NZ59Vb7P2+188>:  mov    eax,DWORD PTR [ebp-0x14]
   0x80488f7 <X1bdrhN8Yk9NZ59Vb7P2+191>:  add    eax,DWORD PTR [ebp+0x8]
   0x80488fa <X1bdrhN8Yk9NZ59Vb7P2+194>:  movzx  eax,BYTE PTR [eax]
   0x80488fd <X1bdrhN8Yk9NZ59Vb7P2+197>:  cmp    al,BYTE PTR [ebp-0x5]
   0x8048900 <X1bdrhN8Yk9NZ59Vb7P2+200>:  je     0x804890a <X1bdrhN8Yk9NZ59Vb7P2+210>
   0x8048902 <X1bdrhN8Yk9NZ59Vb7P2+202>:  mov    eax,DWORD PTR [ebp-0x18]
   0x8048905 <X1bdrhN8Yk9NZ59Vb7P2+205>:  jmp    0x8048a20 <X1bdrhN8Yk9NZ59Vb7P2+488>
   0x804890a <X1bdrhN8Yk9NZ59Vb7P2+210>:  add    DWORD PTR [ebp-0x14],0x1
   0x804890e <X1bdrhN8Yk9NZ59Vb7P2+214>:  mov    eax,DWORD PTR [ebp-0x14]

Видите ли вы те же закономерности, что вижу я? Если нет — не беда.
Здесь в программе проверяется мой ввод поксоренный с константами.
Теперь ещё раз посмотрим на ввод, первые байты ксорятся с некоторыми константами, и затем вывод сравнивается с другими костантами.
Последние две функции должны выглядеть как-то так:

void PJeGPC4TIVaKFmmy53DJ (int * p)
{
  int array[] = {0xe4,0x87,0xfb,0xbe,0xc9,0x93,0x84,0xfc,0x8d,0xe5,0xbf,0x5c,0xe2,0x76,0x21,0xb8}
  for(i=0;i<16;i++)
 {
    p[i] = p[i] ^ array[i]
 }
}
int X1bdrhN8Yk9NZ59Vb7P2(int * p)
{
   int array = {0xd9,0xcd,0xc9,0xe5,0x9e,0xd0,0xe8,0xa5,0xaf,0x87,0xd2,0x79,0xa9,0x5d,0x7,0x81}
   for(i=0;i<16;i++)
 {
    if(p[i] != array[i])
         return false; // fail..
 }
  return true 
}

Я набросал скрипт на Python чтобы применить XOR к этим константам и нашёл ключ:

#!/usr/bin/python
firstConst = [0xe4,0x87,0xfb,0xbe,0xc9,0x93,0x84,0xfc,0x8d,0xe5,0xbf,0x5c,0xe2,0x76,0x21,0xb8]
secondConst = [0xd9,0xcd,0xc9,0xe5,0x9e,0xd0,0xe8,0xa5,0xaf,0x87,0xd2,0x79,0xa9,0x5d,0x7,0x81]
ret =""
for x in range(16):
        ret+=chr(firstConst[x] ^ secondConst[x])
print ret

eren@lisa:~$ ./CrackTheDoor

*** DOOR CONTROL SYSTEM ***

PASSWORD: =J2[WClY«bm%K+&9

*** ACCESS GRANTED ***

*** THE DOOR OPENED ***

Voilà!

Компания прислала мне вторую часть, так что вскоре я напишу ещё одну статью.
Share post

Similar posts

AdBlock has stolen the banner, but banners are not teeth — they will be back

More
Ads

Comments 61

    –20
    Гениально! :)
      +53
      Извините, а что здесь гениального?
        0
        Гениально то, что автор собеседуется на позицию инженера программной безопасности, и при этом запускает неизвестные программы под рутом (;
        судя по

        root@lisa:~# ./CrackTheDoor


        UPD: я буду читать комментарии…
          +35
          Рут на виртуалке — это Серьёзно. Нельзя запускать ничего из-под Рута на инстансе, который живёт 5 минут. Ведь это же Рут.
            –3
            внизу уже ответили за меня…
              –5
              ну понятно что в виртуалке, но так же понятно что нет никаких причин чтобы производить исследование под рутом, а значит он сделал это по привычке… плохая привычка для безопасника, не находите?
                –1
                те кто не согласен, вы считаете что работа под рутом это хорошая привычка или вы считаете что под рутом были основания работать, никак не пойму с чем конкретно не согласны…
          +10
          Если бы был не просто XOR, а комбинация хотя бы ADD и XOR — это был бы… ну, крякмис начального уровня.
          Ну и в целом. В данной проге достаточно пропатчить один бит (заменить je на jne по адресу 0x8048898) и, в общем, всё.
            +8
            Ну, справедливости ради стоит сказать, что в крякерской среде, замена условных переходов на безусловные считается грязным хаком и признаком дурного тона, если угодно. В статье написано, что попросили найти пароль, а не тупо «открыть дверь».
              +4
              И не получить работу, ибо это не то что требовалось.
            +66
            «Компания прислала мне вторую часть, так что вскоре я напишу ещё одну статью.»

            Во второй части статьи:

            «Компания прислала мне третью часть, так что вскоре я напишу ещё одну статью.»

            Срочно пускай берут в штат или заключают договор подряда! Нельзя работать бесплатно под предлогом «собеседования». :)
              +142
              Компания прислала третью часть. Оказалось, я попал в неподходящую компанию и теперь иду по статье.
                +3
                Ну, пример-то явно учебный…
                +1
                а в IDA/hex rays это не проще было сделать?
                  +10
                  IDA и Hex-Rays надо вначале купить, не?
                    +1
                    Ида точно есть бесплатная, но вот есть ли в ней загрузчик ELFов — вопрос.
                    +8
                    Когда это было проблемой для инженера по безопасности?
                      0
                      IDA 5.0 бесплатна (без Hex-Rays, разумеется)
                    +28
                    Тут одного тоже попросили…

                    У вас не так было?
                    image
                      +1
                      мм, что за кино?
                        +16
                        SWORDFISH, это ж культовый фильм ))
                          –3
                          Ну я бы так не сказал ) Культовые фильмы с Анжелиной, Сандрой и Киану, а этот на другое поколение и целевую аудиторию рассчитан )
                          +68
                          Он вообще интересный.

                      +26
                      Соискатель на позицию безопасника запускает неизвестные файлы под рутом?
                        +1
                        Скорее всего в виртуалке
                          0
                          А зачем даже в виртуалке запускать от рута? Тем более что дальше идут запуски от обычного пользователя (включая и финальный запуск со вводом правильного пароля), а значит рут в принципе не требовался.
                            +14
                            Вот интересна логика минусующих. Мол, если виртуалка, то можно и из-под рута, да? А ничего, что программа, будучи запущенной из-под рута, могла, скажем, пропатчить основные отладочные утилиты (gdb, strace, ldd), что сделало бы задачу… м-м-м… скажем так, еще более увлекательной?
                          0
                          del
                            0
                            Но я думаю не на продакшен же сервере… Специально поднятая виртуалка как вариант.
                              +21
                              Специально поднятый продакшен сервер. Это серьёзная игра!
                            +3
                            Я поставил breakpoint на PJeGPC4TIVaKFmmy53DJ

                            До этого это имя вроде не упоминается. Откуда оно?
                              0
                              Я не особо много пользовался gdb, но предположу, что это какой-то алиас к адресу. Вот эта строчка:
                              => 0x08048534 <PJeGPC4TIVaKFmmy53DJ+0>
                                0
                                Я тоже, но предполагаю что это обфусцированное название функции.
                                И строчка эта указана уже после того как был установлен брекпоинт.
                                  0
                                  Как понять обфусцированное название функции? Название функции можно получить только в паре случаев: экспортированное имя, наличие отладочной информации рядом (pdb, к примеру) [возможны еще ситуации, но слишком много нюансов]. Названия функций не хранятся в скомпилированных приложениях.
                                    +7
                                    В Unix-мире — хранятся, если их специально не вырезать.
                                    root@lisa:~# file CrackTheDoor
                                    CrackTheDoor: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.15, BuildID[sha1]=0x9927be2fe310bea01d412164103b9c8b2d7567ea, not stripped
                                      +1
                                      Тогда минусуйте мой следующий коммент про нейминг из читабельных символов к хренам, проверить не мог — с мобилы, но не думал что такая подстава с именами фунок будет.
                                0
                                Оба имени рождены из двух наборов байт (в ASCII), образующих 16-байтовые массивы для функций (де)шифрования. Автору было так проще ориентироваться, это его нейминг. Updated: Ну, не прям из них, но частично. Он просто скопировал из hex-viewer'а читабельные символы этой области, скорее всего.
                                  0
                                  Автору программы или статьи?
                                  Я так понимаю что это нейминг автора программы.
                                  Я не понял где присваивается или узнается этот нейминг.
                                  0
                                  del
                                  +3
                                  По сути Вы использовали gdb только в качестве дизассемблера. Для этого проще использовать objdump. И не нужно обходить ptrace.
                                    +1
                                    А почему у него в первый раз программа упала, а во второй он получил точку входа?
                                      +5
                                      В первый раз он использовал gdb 'r' (run) — запустил ее под отладчиком просто, потом gdb 'info file' — получил информацию об исполняемом файле, в том числе его точку входа.
                                        –7
                                        Потому что он настроил анти-антиотладку
                                      • UFO just landed and posted this here
                                          0
                                          Запускать неизвестные бинарники из-под рута? Мужик, ты не прошел собеседование.
                                            +7
                                            Кстати, идея для подобного бинарника: можно ведь в системе немного подменить gdb, чтобы он немного глючил, и/или strace, ну и вообще подобные какие-нибудь программы. Понятное дело, что придётся предусмотреть разные дистры и вот это всё, но результат может быть забавным.
                                              +3
                                              В перспективе — инициирует запуск Skynet и отправку роботов-терминаторов из будущего по адресу кандидата. Так, мысли вслух… :)
                                            0
                                            If you want to try it yourself, send me an email for binary.

                                            А кто-нибудь запросил бинарик у автора для тренировки?
                                              +1
                                              crackmes.de — выбирай любой из тысяч. Там есть такие, от которых волосы дыбом встанут.
                                              +3
                                              А нельзя было в момент запроса пароля сделать core файл командой gcore, потом загрузить его в gdb, подняться вверх по стеку и дальше смотреть по контексту что там делается?
                                                +6
                                                Как по мне — очень странно, что такое дают на собеседованиях. На crackmes.de есть множество таких крякми, незатейливо использующих xor (у всех сложность 1 / 9).
                                                И в чём заключается работа инженера программной безопасности, если не секрет?
                                                  +19
                                                  Работа заключается в написании крякми для новых кандидатов.
                                                    –1
                                                    Для нового кандидата.
                                                  0
                                                  Поделился бы что ли бинарником, чтобы другие тоже могли поковырять…
                                                  • UFO just landed and posted this here
                                                    • UFO just landed and posted this here
                                                        0
                                                        Автору поста: ИМХО код в таком оформлении

                                                        int main()
                                                        {
                                                            if (ptrace(PTRACE_TRACEME, 0, 1, 0) < 0) {
                                                                printf("DEBUGGING... Bye\n");
                                                                return 1;
                                                            }
                                                            printf("Hello\n");
                                                            return 0;
                                                        }
                                                        


                                                        читается гораздо лучше, чем код в таком оформлении:

                                                        int main()
                                                        {
                                                            if (ptrace(PTRACE_TRACEME, 0, 1, 0) < 0) {
                                                                printf("DEBUGGING... Bye\n");
                                                                return 1;
                                                            }
                                                            printf("Hello\n");
                                                            return 0;
                                                        }
                                                          0
                                                          Так 2 часть будет или автор уже получил работу?

                                                        Only users with full accounts can post comments. Log in, please.