+ Reply to Thread
Results 1 to 6 of 6

Thread: PlaidCTF 2014 :: hudak (reverse 250)

  1. #1

    Default PlaidCTF 2014 :: hudak (reverse 250)

    PlaidCTF 2014 :: hudak (reverse 250)

    Пожалуй начну с самого простого (исходя из количества решивших).

    Сэмпл представляет собой ELF 32 бита размером 9640 байт, что относительно не много.

    Задание звучало так: «Can you reverse this program and find out what The Plague was working on?», что ни о чем не говорит кроме как о том, что предстоит реверсить.

    Общая схема приложения следующая:
    1) запрашивается ввод пароля
    Code:
    .text:080484DB                 mov     dword ptr [esp+4], offset rqs ; "Enter the password.\n"
    .text:080484E3                 mov     dword ptr [esp], 1
    .text:080484EA                 call    ___printf_chk
    2) получается пользовательский ввод;
    Code:
    .text:080484EF                 mov     dword ptr [esp+0Ch], 0Ah
    .text:080484F7                 mov     dword ptr [esp+8], 50h
    .text:080484FF                 mov     [esp+4], ebx
    .text:08048503                 mov     dword ptr [esp], 0
    .text:0804850A                 call    read_entry
    3) проверяется длина (30 символов);
    Code:
    .text:08048541                 cmp     edx, 1Eh
    .text:08048544                 jz      short len_ok
    4) отдается на обработку
    Code:
    .text:08048566                 mov     dword ptr [esp], offset FUN_1
    .text:0804856D                 call    XX_constructor
    .text:08048572                 mov     dword ptr [esp], offset FUN_1_1
    .text:08048579                 mov     esi, eax
    .text:0804857B                 call    XX_constructor
    .text:08048580                 mov     [eax+XX.buffer_ptr], ebx
    .text:08048583                 mov     [eax+XX.busy_fl], 1
    .text:08048589                 mov     [esp], eax
    .text:0804858C                 call    XX_get_mem4
    .text:08048591                 mov     [esi+XX.link_YY_ZZ], eax
    .text:08048594                 mov     [esp], esi
    .text:08048597                 call    [esi+XX.fun_ptr]
    5) проверяется результат обработки и чеканья
    Code:
    .text:0804859A                 test    eax, eax
    .text:0804859C                 jz      short msg_wrong
    Сама проверка, дающая значение eax без затей
    Code:
    .text:08048A3E                 mov     dword ptr [esp+8], 1Fh ; n
    .text:08048A46                 mov     dword ptr [esp], offset MASTER ; s1
    .text:08048A4D                 mov     [esp+4], eax    ; s2
    .text:08048A51                 call    _memcmp
    .text:08048A56                 test    eax, eax
    .text:08048A58                 setz    al
    Схема стандартная и в реалии лечится патчем перехода, но нам нужно другое, а именно значение пароля который пройдет преобразование и проверку и будет в итоге игровым флагом. Кода в обработке не так много, но код «мутный». Используется по ходу работы три структуры вида,

    Code:
    00000000 XX              struc ; (sizeof=0x10)
    00000000 busy_fl         dd ?
    00000004 buffer_ptr      dd ?                    ; offset
    00000008 fun_ptr         dd ?                    ; offset
    0000000C link_YY_ZZ      dd ?                    ; offset
    00000010 XX              ends
    00000010
    00000000 ; ---------------------------------------------------------------------------
    00000000
    00000000 YY              struc ; (sizeof=0x8)
    00000000 link_XX1        dd ?                    ; offset
    00000004 link_XX2        dd ?                    ; offset
    00000008 YY              ends
    00000008
    00000000 ; ---------------------------------------------------------------------------
    00000000
    00000000 ZZ              struc ; (sizeof=0xC)
    00000000 link_XX1        dd ?                    ; offset
    00000004 link_XX2        dd ?                    ; offset
    00000008 link_XX3        dd ?                    ; offset
    0000000C ZZ              ends
    под каждый экземпляр которых алочится память, сами структуры завязываются в длинные списки, хранят указатели на функции этапов обработки, указатели на буферы и их части… и вся работа идет на основе этих списков. Желающие могут посмотреть приложенную базу от IDA (не знаю у всех ли откроется).

    В процессе обработки строка, введенного пароля, размножается в необходимом количестве с циклическим сдвигом ее содержимого влево. Затем массив этих строк сортируется от меньшего значения к большему. И в порядке отсортированных строк из них в результирующую строку выбираются последние символы. И перед проверкой эта строка по всей длине ксорится значением 0х37. Вроде не сложно, но посмотрим на практике.

    Код на python выполняющий аналогичные действия не впечатляет

    Code:
    #! /usr/bin/python
    # -*- coding: utf-8 -*-
    
    pass_ = 'it_might_be_your_password'
    
    array_str = []
    for i in range(len(pass_)):
       array_str.append(pass_[i:]+pass_[:i])
    
    array_str.sort()
    
    _out_hex = ''
    for i in range(len(pass_)):
       c = ord(array_str[i][-1]) ^ 0x37
       _out_hex += '%02X '%c
    
    print _out_hex
    Результаты преобразования уже напрягают (не согласным с этим предлагаю не читать дальше, а самим обратить алго).

    Массив сдвинутых строк.
    Code:
    it_might_be_your_password
    t_might_be_your_passwordi
    _might_be_your_passwordit
    might_be_your_passwordit_
    ight_be_your_passwordit_m
    ght_be_your_passwordit_mi
    ht_be_your_passwordit_mig
    t_be_your_passwordit_migh
    _be_your_passwordit_might
    be_your_passwordit_might_
    e_your_passwordit_might_b
    _your_passwordit_might_be
    your_passwordit_might_be_
    our_passwordit_might_be_y
    ur_passwordit_might_be_yo
    r_passwordit_might_be_you
    _passwordit_might_be_your
    passwordit_might_be_your_
    asswordit_might_be_your_p
    sswordit_might_be_your_pa
    swordit_might_be_your_pas
    wordit_might_be_your_pass
    ordit_might_be_your_passw
    rdit_might_be_your_passwo
    dit_might_be_your_passwor
    Он же отсортированный

    Code:
    _be_your_passwordit_might
    _might_be_your_passwordit
    _passwordit_might_be_your
    _your_passwordit_might_be
    asswordit_might_be_your_p
    be_your_passwordit_might_
    dit_might_be_your_passwor
    e_your_passwordit_might_b
    ght_be_your_passwordit_mi
    ht_be_your_passwordit_mig
    ight_be_your_passwordit_m
    it_might_be_your_password
    might_be_your_passwordit_
    ordit_might_be_your_passw
    our_passwordit_might_be_y
    passwordit_might_be_your_
    r_passwordit_might_be_you
    rdit_might_be_your_passwo
    sswordit_might_be_your_pa
    swordit_might_be_your_pas
    t_be_your_passwordit_migh
    t_might_be_your_passwordi
    ur_passwordit_might_be_yo
    wordit_might_be_your_pass
    your_passwordit_might_be_
    Строка, сформированная из последних символов ttrep_rbigmd_wy_uoashios_.

    И результирующая строка CCERGhEU^PZSh@NhBXVD_^XDh.

    Начнем отматывать действия назад и посмотрим на нашу MASTER строку без заключительного расксоривания. Короткий IDA скрипт нам в этом поможет.

    Code:
    auto ea, i, b;
    ea = ScreenEA();
    for(i=0; i<30; i=i+1)
        PatchByte(ea+i, Byte(ea+i)^0x37);
    Теперь можем увидеть из чего должен состоять наш пароль 3.._tvl3\xFFstttwrp__1mea4as4i1_.. Сразу бросается в глаза присутствие в строке символа 0xFF. Во-первых, кто мог бы предполагать о его наличии, во-вторых, как его ввести с клавиатуры в консоли и, в-третьих, вся работа алгоритма (этого нет в повествовании выше) строится на наличии этого символа во входной строке и его местоположении. На этом завязано количество генерируемых структур, количество размножаемых строк, количество сдвигов и т.д. Понятно поначалу в моей строке тоже такого символа не было, и он был найден очень далеко в памяти от начала строки, что вовлекло всю эту память в процесс обработки, увеличило объем трассировки и не добавило понимания процессу. Поначалу стало грустно, алгоритм казался необратимым и была попытка строить пароль из представленных символов работая анаграмными методами, что ближе к криптографии. Ничего в итоге в голову не пришло учитывая написание на leet и я вернулся к обращению алгоритма. Повторное прокручивание короткой выходной строки (без повторяющихся символов) тем же алгоритмом с ручным допиливанием дало возможность получить исходную.

    Code:
    Исходная строка: azbycxd
    
    Сдвиг исходной строки:
    azbycxd
    zbycxda
    bycxdaz
    ycxdazb
    cxdazby
    xdazbyc
    dazbycx
    
    Сортировка строк:
    azbycxd
    bycxdaz
    cxdazby
    dazbycx
    xdazbyc
    ycxdazb
    zbycxda
    
    Выходная строка: dzyxcba
    
    Сдвиг выходной строки:
    dzyxcba
    zyxcbad
    yxcbadz
    xcbadzy
    cbadzyx
    badzyxc
    adzyxcb
    
    Сортировка строк (справа пара символов – 1й из выходной строки, 2й из сортированного массива):
    adzyxcb - da
    badzyxc - zb
    cbadzyx - yc
    dzyxcba - xd
    xcbadzy - cx
    yxcbadz - by
    zyxcbad - az
    
    Итого (az)-(zb)-(by)-(yc)-(cx)-(xd)-(da) => azbycxd
    Проделаем аналогичные действия с нашей выходной строкой:
    Code:
    .._tvl3\xffstttwrp__1mea4as4i1_.3 - 3. 
    .3.._tvl3\xffstttwrp__1mea4as4i1_ - .. 
    ._tvl3\xffstttwrp__1mea4as4i1_.3. - .. 
    1_.3.._tvl3\xffstttwrp__1mea4as4i - _1 
    1mea4as4i1_.3.._tvl3\xffstttwrp__ - t1 
    3.._tvl3\xffstttwrp__1mea4as4i1_. - v3 
    3\xffstttwrp__1mea4as4i1_.3.._tvl - l3 
    4as4i1_.3.._tvl3\xffstttwrp__1mea - 34 
    4i1_.3.._tvl3\xffstttwrp__1mea4as - \xff4 
    _.3.._tvl3\xffstttwrp__1mea4as4i1 - s_ 
    _1mea4as4i1_.3.._tvl3\xffstttwrp_ - t_ 
    __1mea4as4i1_.3.._tvl3\xffstttwrp - t_ 
    _tvl3\xffstttwrp__1mea4as4i1_.3.. - t_ 
    a4as4i1_.3.._tvl3\xffstttwrp__1me - wa 
    as4i1_.3.._tvl3\xffstttwrp__1mea4 - ra 
    ea4as4i1_.3.._tvl3\xffstttwrp__1m - pe 
    i1_.3.._tvl3\xffstttwrp__1mea4as4 - _i 
    l3\xffstttwrp__1mea4as4i1_.3.._tv - _l 
    mea4as4i1_.3.._tvl3\xffstttwrp__1 - 1m 
    p__1mea4as4i1_.3.._tvl3\xffstttwr - mp 
    rp__1mea4as4i1_.3.._tvl3\xffstttw - er 
    s4i1_.3.._tvl3\xffstttwrp__1mea4a - as 
    stttwrp__1mea4as4i1_.3.._tvl3\xff - 4s 
    tttwrp__1mea4as4i1_.3.._tvl3\xffs - at 
    ttwrp__1mea4as4i1_.3.._tvl3\xffst - st 
    tvl3\xffstttwrp__1mea4as4i1_.3.._ - 4t 
    twrp__1mea4as4i1_.3.._tvl3\xffstt - it 
    vl3\xffstttwrp__1mea4as4i1_.3.._t - 1v 
    wrp__1mea4as4i1_.3.._tvl3\xffsttt - _w 
    \xffstttwrp__1mea4as4i1_.3.._tvl3 - .\xff
    Ввиду того, что есть повторяющиеся символы, то это будет не также просто.

    Посчитаем символы. ('e','i','l','m','p','r','v','w','\xff') – по одному; ('1','3','4','a','s') – по два; ('.') – три; ('_','t') – четыре.

    Одиночные символы дают нам однозначную последовательность в парах 'er','it','l3', 'mp', 'pe', 'ra','v3','wa', '\xff4', и уже длинный кусок кода 'mpera'. Для остальных можно присовокупить предыдущий символ '_it','_l3','1v3','_wa','.\xff4','1mpera' одновременно удалив строки со всеми рассмотренными комбинациями из списка. Ну и так далее, что в итоге нам даст строку 4t_l34st_it_was_1mperat1v3...\xff , которая и есть флаг за исключением '\xff'.

    Содержание архива hudak.RAR:
    hudak – сэмпл из задания
    hudak.idb – база для IDA Pro v5.7
    hudak_direct.py – реализация алгоритма модификации входной строки
    hudak.py – построение выходной таблицы для анализа

    That's all Folks!
    Last edited by ximera; 18-04-2014 at 00:27.

  2. 6 пользователя(ей) сказали cпасибо:
    Darwin (15-04-2014) dukeBarman (16-06-2014) korsader (15-04-2014) ololoshenka (18-04-2014) root (15-04-2014) ximera (16-04-2014)
  3. #2

    Default Re: PlaidCTF 2014 :: hudak (reverse 250)

    Вопрос от windows-guy - чем ты трейсил? Gdb или чем-нибудь более удобным?

  4. #3
    ximera's Avatar

    Default Re: PlaidCTF 2014 :: hudak (reverse 250)

    Насколько я знаю использовалась IDA, но не факт.
    Чтобы избегать ошибок, надо набираться опыта; чтобы набираться опыта, надо делать ошибки. © Лоренс Питер

    Неизбежное прими достойно. © Сенека Луций Анней

    Господи... храни сумасшедших. © Сумасшедший Фрэнки

  5. #4

    Default Re: PlaidCTF 2014 :: hudak (reverse 250)

    Quote Originally Posted by ololoshenka View Post
    Вопрос от windows-guy - чем ты трейсил? Gdb или чем-нибудь более удобным?
    IDA (windows host) + linux_server (KALI on vmware) с пропуском ввода и пропатчиванием значений прямо в буфер.

  6. #5

    Default Re: PlaidCTF 2014 :: hudak (reverse 250)

    У меня юзание трейспоинтов через иду в такой связке крашило иду :/
    upd: пресвятые угодники! Наконец-то получилось сделать так, чтобы ида показывала графы в дебаг моде. Удобно то как (и таск этот раскрутил быстро!)
    Last edited by ololoshenka; 21-04-2014 at 11:49.

  7. #6

    Default Re: PlaidCTF 2014 :: hudak (reverse 250)

    Почитал райтап к этому таску от Dragon Sector. Оказалось что в таске было использовано преобразование Барроуза — Уилера используемое в техниках сжатия для преобразования исходных данных. И понятно, оно обратимо, без допиливания напильником.

    Обратное преобразование из увиденного в вики на питоне будет выглядеть так:
    Code:
    #! /usr/bin/python
    # -*- coding: utf-8 -*-
    
    pass_ = '3.._tvl3\xFFstttwrp__1mea4as4i1_.'
    
    array_str = []
    for i in range(len(pass_)):
       array_str.append(pass_[i])
    print array_str
    
    for j in range(len(pass_)-1):
      sorted_array_str = []
      for i in range(len(pass_)):
         sorted_array_str.append(array_str[i])
      sorted_array_str.sort()
    
      for i in range(len(pass_)):
         array_str[i] += sorted_array_str[i][j]
    
    print array_str[len(pass_)-1][2:]+array_str[len(pass_)-1][0]
    Как говорится "Учите матчасть" и не изобретайте велосипед.

  8. 3 пользователя(ей) сказали cпасибо:
    Darwin (07-05-2014) dukeBarman (16-06-2014) skankhunt (07-10-2016)
+ Reply to Thread

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
All times are GMT. The time now is 01:30
vBulletin® Copyright ©2000 - 2018
www.reverse4you.org