インタビューのためにプログラムをハックするように頼まれました。 パート2

これは、出版物の第2部の翻訳です。 「インタビューのためにプログラムをハッキングするように頼まれました 元のテキストはここにあります



まえがき



みなさん、こんにちは。 「パート2」の意味がわからない場合は、 パート1をお読みください。

最初に、最初の部分を読んだすべての人に感謝したいと思います。なぜなら、最終的に多くの素晴らしいフィードバックを得たからです。



また、いくつかの誤解を排除したいと思います。

  1. 私はこの会社で働いていません。バルセロナに引っ越しました。
  2. このインタビューはほぼ1年前に行いました。
  3. クラウドのプログラムをクラックしました(関税5ドル、はい、あなたは会社を推測しました)ので、 root @ 'aを使用することは問題ではないと思います-数秒で新しい環境を再作成できます。 最終的に、gdbはroot intファイルを受け入れなかったため、ユーザーeren @に切り替えました。
  4. 記事の最後を読むことを忘れないでください-あなたはそれを愛するでしょう!


行こう



今回はドアではなく、 核ミサイルで作業します。



eren@lisa:~$ ./CrackTheNuke *** NUKE CONTROL SYSTEM *** PASSWORD: giveMeNuke *** ACCESS DENIED *** PASSWORD: iwantanexplosion *** ACCESS DENIED *** PASSWORD: knockknockitsme *** ACCESS DENIED *** *** SYSTEM LOCKED *** *** SHUTTING DOWN *** eren@lisa:~$
      
      





サンプルとしてintel asm構文を使用してバイナリ全体をダンプします。



 eren@lisa:~$ objdump -M intel -D CrackTheNuke > staticDis eren@lisa:~$
      
      







このファイルは後で必要になります。 staticDisファイルを調べると、 intelの構文で完全なダンプを見つけることができます。



今回は別のことを試してみましょう。最初にプロセスを開始し、その後、デバッガを選択します。



 eren@lisa:~$ ./CrackTheNuke *** NUKE CONTROL SYSTEM *** PASSWORD:
      
      







これで、別のシェルに切り替えて、そこからデバッガーを実行できます。



 eren@lisa:~$ ps aux | grep Crack eren 4741 0.0 0.0 1724 252 pts/0 S+ 14:54 0:00 ./CrackTheNuke eren 4845 0.0 0.1 7832 832 pts/1 S+ 14:56 0:00 grep Crack eren@lisa:~$ gdb --pid 4741 GNU gdb (GDB) 7.4.1-debian Copyright (C) 2012 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "x86_64-linux-gnu". For bug reporting instructions, please see: <http://www.gnu.org/software/gdb/bugs/>. Catchpoint 1 (syscall 'ptrace' [26]) Attaching to process 4741 Reading symbols from /home/eren/CrackTheNuke...(no debugging symbols found)...done. Reading symbols from /lib32/libc.so.6...(no debugging symbols found)...done. Loaded symbols for /lib32/libc.so.6 Reading symbols from /lib/ld-linux.so.2...(no debugging symbols found)...done. Loaded symbols for /lib/ld-linux.so.2 0xf7726430 in __kernel_vsyscall () => 0xf7726430 <__kernel_vsyscall+16>: 5d pop ebp (gdb)
      
      







これで、前のウィンドウで任意の16文字を入力して、ここに戻ることができます。 glibcライブラリにあるscanf関数になりました( crackmeはscanfを16回呼び出しますが、ここで時間を節約します)。



gdbでは、 siと入力できます(abbr。from single step )。 アドレス0x80495edに到達するまでsiを入力します。 または、単純に次のコマンドを入力することもできます: b * 0x80495ed



そして



を押して目的のアドレスに到達します。



いずれにせよ、私たちは現在適切に配置されています。



 0x80495ed <main+195>:
      
      







ここで比較操作を見ることができます:



 0x80495ed <main+195>: cmp DWORD PTR [esp+0x1c],0x0
      
      







gdbでは、 p/x $esp



してp/x $esp



の内容を表示できます。

レジスタとアドレスを使用していくつかの計算を行うこともできます: p/x $esp+0x1c



。 または、 p/x *0xff811bac



に名前を変更した後、アドレスの内容を表示します。



ここにsiを入力できます。これは、 crackmeが16文字を受け取り、行終了文字を期待する瞬間につながります\ n



0x804962dにブレークポイントを配置することをお勧めします。長くてb * 0x804962d



して待ちたくない場合は、 b * 0x804962d



です。



そして今、楽しみが始まります:



 => 0x804962d <main+259>: push eax 0x804962e <main+260>: push ebx 0x804962f <main+261>: rdtsc 0x8049631 <main+263>: and eax,0xfffff 0x8049636 <main+268>: test eax,eax 0x8049638 <main+270>: je 0x8049646 <g99> 0x804963a <main+272>: xor ebx,0xe 0x804963d <main+275>: add ebx,0xe 0x8049640 <main+278>: sub ebx,0xe 0x8049643 <main+281>: dec eax
      
      







rdtscマニュアルを聞いたことがありますか? その主なタスクは、プロセッササイクルの数をカウントすることです。 rdtscを呼び出した後 TSCカウンターはedxおよびeaxレジスタに配置されます。



 0x8049636 <main+268>: test eax,eax 0x8049638 <main+270>: je 0x8049646 <g99>
      
      







Cでも同じことが次のようになります。



 if(eax == 0) { goto 0x8049646 }
      
      







eaxは 0でないため、掘り続けます。 お気づきのように、以下のコードは完全なゴミです。0xeebxに追加してから減算します。 彼らは私たちを混乱させようとしているようです。



 xor ebx,0xe add ebx,0xe sub ebx,0xe dec eax
      
      







eaxが0の間、このサイクルを続けます。

ブレークポイントを設定します: b * 0x8049646



およびcを押します

さて、面白いものは何もありません。



 => 0x80494db <nkc1qpE2L6f6AyqaendA>: push ebp 0x80494dc <nkc1qpE2L6f6AyqaendA+1>: mov ebp,esp 0x80494de <nkc1qpE2L6f6AyqaendA+3>: sub esp,0x14 0x80494e1 <nkc1qpE2L6f6AyqaendA+6>: mov DWORD PTR [ebp-0x4],0x0 0x80494e8 <nkc1qpE2L6f6AyqaendA+13>: mov DWORD PTR [esp],0x0 0x80494ef <nkc1qpE2L6f6AyqaendA+20>: call 0x804944b <qEWL8Jl0zdpmTbwhziDv> 0x80494f4 <nkc1qpE2L6f6AyqaendA+25>: mov eax,DWORD PTR [ebp+0x8] 0x80494f7 <nkc1qpE2L6f6AyqaendA+28>: mov DWORD PTR [esp],eax 0x80494fa <nkc1qpE2L6f6AyqaendA+31>: call 0x8048604 <fjDKIzPtGuE8ZdfSL8vq> 0x80494ff <nkc1qpE2L6f6AyqaendA+36>: mov DWORD PTR [esp],0x2 0x8049506 <nkc1qpE2L6f6AyqaendA+43>: call 0x804944b <qEWL8Jl0zdpmTbwhziDv> 0x804950b <nkc1qpE2L6f6AyqaendA+48>: mov eax,DWORD PTR [ebp+0x8] 0x804950e <nkc1qpE2L6f6AyqaendA+51>: mov DWORD PTR [esp],eax 0x8049511 <nkc1qpE2L6f6AyqaendA+54>: call 0x8048ab1 <W0ElBw5Smo9TPiWOeK8c> 0x8049516 <nkc1qpE2L6f6AyqaendA+59>: mov DWORD PTR [ebp-0x4],eax 0x8049519 <nkc1qpE2L6f6AyqaendA+62>: mov DWORD PTR [esp],0x1 0x8049520 <nkc1qpE2L6f6AyqaendA+69>: call 0x804944b <qEWL8Jl0zdpmTbwhziDv> 0x8049525 <nkc1qpE2L6f6AyqaendA+74>: mov eax,DWORD PTR [ebp-0x4] 0x8049528 <nkc1qpE2L6f6AyqaendA+77>: leave 0x8049529 <nkc1qpE2L6f6AyqaendA+78>: ret
      
      





nkc1qpE2L6f6AyqaendA



この関数はプロセス全体の基礎です。



nkc1qpE2L6f6AyqaendAが参照するすべての関数を調べてみましょう: qEWL8Jl0zdpmTbwhziDvfjDKIzPtGuE8ZdfSL8vqおよびW0ElBw5Smo9TPiWOeK8c



 (gdb) x/10i qEWL8Jl0zdpmTbwhziDv 0x804944b <qEWL8Jl0zdpmTbwhziDv>: push ebp 0x804944c <qEWL8Jl0zdpmTbwhziDv+1>: mov ebp,esp 0x804944e <qEWL8Jl0zdpmTbwhziDv+3>: mov eax,DWORD PTR [ebp+0x8] 0x8049451 <qEWL8Jl0zdpmTbwhziDv+6>: cmp eax,0x0 0x8049454 <qEWL8Jl0zdpmTbwhziDv+9>: je 0x80494b9 <hzdhp> 0x8049456 <qEWL8Jl0zdpmTbwhziDv+11>: cmp eax,0x1 0x8049459 <qEWL8Jl0zdpmTbwhziDv+14>: je 0x8049499 <qEWL8Jl0zdpmTbwhziDv+78> 0x804945b <qEWL8Jl0zdpmTbwhziDv+16>: call 0x8047b71 0x8049460 <qEWL8Jl0zdpmTbwhziDv+21>: add DWORD PTR [eax+0x48604bf],0x5eb9008 0x804946a <qEWL8Jl0zdpmTbwhziDv+31>: add DWORD PTR [eax-0x4608ea13],0x8048ab1 (gdb) x/10i fjDKIzPtGuE8ZdfSL8vq 0x8048604 <fjDKIzPtGuE8ZdfSL8vq>: call 0xb027:0xaf72c78c 0x804860b <fjDKIzPtGuE8ZdfSL8vq+7>: cmp esi,DWORD PTR ds:0xe4dfbbf1 0x8048611 <fjDKIzPtGuE8ZdfSL8vq+13>: (bad) 0x8048612 <fjDKIzPtGuE8ZdfSL8vq+14>: and al,BYTE PTR [ebp+edi*2-0x8] 0x8048616 <fjDKIzPtGuE8ZdfSL8vq+18>: push ebx 0x8048617 <fjDKIzPtGuE8ZdfSL8vq+19>: push esi 0x8048618 <fjDKIzPtGuE8ZdfSL8vq+20>: inc edx 0x8048619 <fjDKIzPtGuE8ZdfSL8vq+21>: mov WORD PTR [ebp+0x76],ss 0x804861c <fjDKIzPtGuE8ZdfSL8vq+24>: xchg edx,eax 0x804861d <fjDKIzPtGuE8ZdfSL8vq+25>: mov al,ds:0x45fd3fbb (gd (gdb) x/10i W0ElBw5Smo9TPiWOeK8c 0x8048ab1 <W0ElBw5Smo9TPiWOeK8c>: call 0xb023:0x1c72c78c 0x8048ab8 <W0ElBw5Smo9TPiWOeK8c+7>: cmp esi,DWORD PTR ds:0xe4dfbbf1 0x8048abe <W0ElBw5Smo9TPiWOeK8c+13>: jmp 0xf86e358 0x8048ac3 <W0ElBw5Smo9TPiWOeK8c+18>: xchg ax,ax 0x8048ac5 <W0ElBw5Smo9TPiWOeK8c+20>: out dx,eax 0x8048ac6 <W0ElBw5Smo9TPiWOeK8c+21>: dec ebp 0x8048ac7 <W0ElBw5Smo9TPiWOeK8c+22>: xchg edi,eax 0x8048ac8 <W0ElBw5Smo9TPiWOeK8c+23>: popa 0x8048ac9 <W0ElBw5Smo9TPiWOeK8c+24>: test DWORD PTR [ecx-0x7e],esp 0x8048acc <W0ElBw5Smo9TPiWOeK8c+27>: test DWORD PTR [edi],esi
      
      







:私たちが見ることができるように、基本的なアルゴリズムはnkc1qpE2L6f6AyqaendA関数内で、次のように鎖であり呼び出すqEWL8Jl0zdpmTbwhziDv -> fjDKIzPtGuE8ZdfSL8vq -> qEWL8Jl0zdpmTbwhziDv -> W0ElBw5Smo9TPiWOeK8c -> qEWL8Jl0zdpmTbwhziDv







各関数の最初の10行を見て、何か異常なものを見つけられますか? fjDKIzPtGuE8ZdfSL8vqおよびW0ElBw5Smo9TPiWOeK8cの最初の行を注意深く見てください。これらはまったく意味がありません



私は今までにない(翻訳者から:元: 人生:) -悪名高い携帯電話会社への言及である可能性が高い)私はこのようなものに遭遇したことがない: call 0xb023:0x1c72c78c



。 そして問題は、これらの関数は両方とも暗号化されており、 gdbはそれらを逆アセンブルしようとしたことです。



そのため、 qEWL8Jl0zdpmTbwhziDvは関数の復号化を処理します(そのため、関数の前に呼び出されます)。



暗号化された関数を復号化された通信に置き換えてプログラム実行アルゴリズムを変更し、qEWL8Jl0zdpmTbwhziDv呼び出しを削除しようとします。



これに基づいて、新しいアルゴリズムは次のようになります: fjDKIzPtGuE8ZdfSL8vq -> W0ElBw5Smo9TPiWOeK8c



それだけです。



行き止まり1.開始



このcrackmeの作業中に、 TimeStampCounterを無効にするか、何らかの方法で制御しようとしました。 この場合、 rdtscは命令の実行間の時間間隔を確認するために使用されます。 したがって、 gdbを介してプログラムを実行しようとすると、この間隔は通常よりもはるかに長くなりますが、通常のコード操作を使用します。 したがって、私はTSCカウンタを制御する方法を見つけようとしましたが、残念ながら、それはプロセッサによって制御されているため、OSの下では何もできません。

しかし、それでも、値を0に設定して、カウンターにヒットするカーネル用のモジュールを作成しようとしました。



 #include <linux/module.h> // included for all kernel modules #include <linux/kernel.h> // included for KERN_INFO #include <linux/init.h> // included for __init and __exit macros #include <linux/kthread.h> // for threads #include <linux/sched.h> // for task_struct #include <linux/time.h> // for using jiffies #include <linux/timer.h> MODULE_LICENSE("GPL"); MODULE_AUTHOR("m00dy"); MODULE_DESCRIPTION("A Fake rdtsc emulation"); static struct task_struct *thread1; int thread_fn(){ uint32_t hi,lo; unsigned long j0,j1; int delay = HZ / 250; hi=0; lo=0xb; printk(KERN_INFO "In thread1"); j0 = jiffies; j1 = j0 + delay; asm volatile("wrmsr"::"c"(0x10),"a"(lo),"d"(hi)); while(1){ if(time_before(jiffies,j1)) schedule(); else { j1 = jiffies + delay; asm volatile("wrmsr"::"c"(0x10),"a"(lo),"d"(hi)); } } } static int __init hello_init(void) { char our_thread[8]="thread1"; printk(KERN_INFO "in init"); thread1 = kthread_create(thread_fn,NULL,our_thread); if((thread1)) { printk(KERN_INFO "in if"); wake_up_process(thread1); } return 0; } static void __exit hello_cleanup(void) { printk(KERN_INFO "Fake RDTSC end \n"); } module_init(hello_init); module_exit(hello_cleanup);=
      
      







残念ながら、この方法は必要に応じて機能せず、検索を続けました。



行き止まり1.終了



両方の機能が復号化された状態になったときにプログラムを停止するというアイデアがありました。 たとえば、これは関数fjDKIzPtGuE8ZdfSL8vqの終わりであるため、 0x8048ab0は非常に良い場所です



.gdbinitを開いて記述してみましょう。



 set disassembly-flavor intel set disassemble-next-line on handle SIGTRAP noprint pass nostop b * 0x8048ab0
      
      







crackmeを再起動し、再びgdbをフックします 。 16文字を入力してcを押します



 => 0xf7706430 <__kernel_vsyscall+16>: 5d pop ebp (gdb) c Continuing. Program received signal SIGSEGV, Segmentation fault. 0x08048ab1 in W0ElBw5Smo9TPiWOeK8c () => 0x08048ab1 <W0ElBw5Smo9TPiWOeK8c+0>: 9a 8c c7 72 1c 23 b0 call 0xb023:0x1c72c78c (gdb) x/10i fjDKIzPtGuE8ZdfSL8vq 0x8048604 <fjDKIzPtGuE8ZdfSL8vq>: push ebp 0x8048605 <fjDKIzPtGuE8ZdfSL8vq+1>: mov ebp,esp 0x8048607 <fjDKIzPtGuE8ZdfSL8vq+3>: call 0x8047b08 0x804860c <fjDKIzPtGuE8ZdfSL8vq+8>: xor eax,0x20ec8390 0x8048611 <fjDKIzPtGuE8ZdfSL8vq+13>: call 0x8047b08 0x8048616 <fjDKIzPtGuE8ZdfSL8vq+18>: xor eax,0x32ff45c6 0x804861b <fjDKIzPtGuE8ZdfSL8vq+23>: call 0x8047b08 0x8048620 <fjDKIzPtGuE8ZdfSL8vq+28>: xor eax,0xdafe45c6 0x8048625 <fjDKIzPtGuE8ZdfSL8vq+33>: call 0x8047b08 0x804862a <fjDKIzPtGuE8ZdfSL8vq+38>: xor eax,0xdbfd45c6 (gdb)
      
      







出来上がり。 これで、クリーンな関数fjDKIzPtGuE8ZdfSL8vqができました 。 しかし、 gdbにはまだ問題があります - 誤ったアセンブリ (英語でここから読むことができます )。



関数を一時ファイルに保存しましょう(パラメーター:file_name、start_address、end_address):



 dump ihex memory fjDKIzPtGuE8ZdfSL8vq_dump 0x8048604 0x8048ab0
      
      







次に、2番目の関数についても同じことを行います。アドレス0x08048e14にブレークポイントを設定し、ダンプを作成します。



 dump ihex memory W0ElBw5Smo9TPiWOeK8c_dump W0ElBw5Smo9TPiWOeK8c g999+3
      
      







両方の機能が揃ったので、プログラム実行アルゴリズムを変更してみましょう。 これを行うには、.gdbinitファイルをクリアし、ブレークポイントを設定します: 0x80494db



 set disassembly-flavor intel set disassemble-next-line on break * 0x80494ef commands set($eip) = 0x80494f4 continue end break * 0x80494fa commands restore fjDKIzPtGuE8ZdfSL8vq_dump restore W0ElBw5Smo9TPiWOeK8c_dump continue end break * 0x08049506 commands set($eip) = 0x804950b continue end break * 0x8049520 commands set($eip) = 0x8049525 continue end
      
      







さて、アルゴリズムを変更したので、すべてが非常に簡単です。 この記事の最初の部分の指示に従ってください。



入力した文字は、特定の定数とのXORであり、その後、結果が正しいかどうかがチェックされます: Inputs ^ FirstConstants == SecondConstants



、それぞれ: Inputs = SecondConstants ^ FirstConstants







そして、ここにキージェネレーターがあります。



 #!/usr/bin/python firstConst = [0x32,0xda,0xdb,0x1,0xf3,0x77,0x4c,0x57,0xbe,0x49,0xec,0x5f,0xab,0x7f,0xed,0x9f] secondConst = [0x0d,0xef,0xf1,0x4d,0xb6,0x4c,0x69,0x20,0xf9,0x20,0xdd,0x7c,0xda,0x3b,0xc9,0xaf] ret ="" for x in range(16): ret+=chr(firstConst[x] ^ secondConst[x]) print ret
      
      







確認しましょう:



 eren@lisa:~$ ./CrackTheNuke *** NUKE CONTROL SYSTEM *** PASSWORD: ?5*LE;%wGi1#qD$0 *** ACCESS GRANTED *** *** THE NUKE STOPPED *** eren@lisa:~$
      
      







すべてが機能します。



おわりに



また、私が採用された後に何が起こったのかをお話ししたいと思います。 私の新しい仕事の最初の日に、彼らは私の部署を変更することを決めました(なぜこの会社がトルコで最高の会社であると考えるのか、まだ理解できません)。



その後、私はJ2ee開発者になりました。 eclipsesvn 、さらにはWindows *というオペレーティングシステムを使用する必要がありました。 しかし、後に判明したように、最悪ではありませんでした。 後で彼らは私にCSSを書かせました...



でも今はバルセロナに住んでいて、素晴らしい人生を送っています。



All Articles