pwnable共謀:ライトアップ


これはデバッグを実行し、Cコード(私は本当に知っていない)を読んで良いです楽しい挑戦.
共謀はあなたのコード化されたパスワードより同じ署名を持っているメッセージを与えています.あなたのパスワードがハッシュ関数Xでデータベースでコード化された方法で保存されるように、あなたがサービスにログインするとき、あなたはあなたのパスワードをXにハッシュして、データベースでチェックされます.あなたが直接Xに等しいハッシュYを与えるならば、あなたはパスワードを見つけることなくログインすることができました.例えば、MD 5はそれに弱いです(他の暗号も).これはハッシュの計算の制限によるものだと思います.
メインコードは以下の通りです.
#include <stdio.h>
#include <string.h>
unsigned long hashcode = 0x21DD09EC;
unsigned long check_password(const char* p){
    int* ip = (int*)p;
    int i;
    int res=0;
    for(i=0; i<5; i++){
        res += ip[i];
        printf(res);
    }
    return res;
}

int main(int argc, char* argv[]){
    if(argc<2){
        printf("usage : %s [passcode]\n", argv[0]);
        return 0;
    }
    if(strlen(argv[1]) != 20){
        printf("passcode length should be 20 bytes\n");
        return 0;
    }

    if(hashcode == check_password( argv[1] )){
        system("/bin/cat flag");
        return 0;
    }
    else
        printf("wrong passcode.\n");
    return 0;
}
ここから面白いセクションが2つあります.
unsigned long hashcode = 0x21DD09EC;
このセクションはグローバル変数hashcodeを定義します.後でそれに取り戻そう.
unsigned long check_password(const char* p){
    int* ip = (int*)p;
    int i;
    int res=0;
    for(i=0; i<5; i++){
        res += ip[i];
        printf(res);
    }
    return res;
}
この関数は文字(すなわち文字列)を取得し、それをベクトル(すなわち配列)にキャストします.それはint* ip = (int*)p;のセクションです.それはここでの仕事に非常に中心的なので、間違いなくread more必要があります.
その後、ループは、ベクトルを反復し、ipのすべての値を取得し、結果を返すに合計します.
その後、main()は機能します:
int main(int argc, char* argv[]){
    if(argc<2){
        printf("usage : %s [passcode]\n", argv[0]);
        return 0;
    }
    if(strlen(argv[1]) != 20){
        printf("passcode length should be 20 bytes\n");
        return 0;
    }

    if(hashcode == check_password( argv[1] )){
        system("/bin/cat flag");
        return 0;
    }
    else
        printf("wrong passcode.\n");
    return 0;
}
3段階で説明します.
  • コマンドラインコール
  • に対して厳密に1つの引数があるかどうかを調べます.
  • 引数は20バイト長
  • でなければなりません
  • 与えられたパスワードがhashcodeに等しいならば、我々は挑戦をpwnedしました.

  • ここから何をしますか.0x21DD09ECは、我々の最初の手掛かりです.私たちはそれで多くのことをすることができません、これを小数点(それは後で意味をなします)で変えましょう.
    Python 3.9.1 (default, Dec 13 2020, 11:55:53)  [GCC 10.2.0] on linux
    Type "help", "copyright", "credits" or "license" for more information.
    >>> 0x21DD09EC
    568134124
    >>> 
    
    その後、check_passwordは我々の第2ステップです.
    ループは5回経過し、結果を返します.つまり、関数を与えるものは、5倍に追加されます.
    568134124 = 5x
    
    Then:
    568134124 / 5 = x
    
    でも!
    >>> 568134124 / 5
    113626824.8
    
    ここでは浮動小数点ではなく整数で動作する必要があります.次に、剰余や関数を入力する式を変更しましょう.
    568134124 = 4x + x'
    
    (おそらくそれをするためのより多くのまじめな方法があります、コメントで私に知らせてください、私はかなり前に学校を去りました)
    >>> 568134124 // 5
    113626824
    
    Then:
    568134124 = 4 * 113626824 + x'
    568134124 - (4 * 113626824) = x'
    113626828 = x'
    
    テストする
    >>> 568134124 == (4 * 113626824) + 113626828
    True
    
    良い.悪用を書きましょう.そのために、pwntoolsを使います.
    2つの小数点のセクションはリトルエンディアンと32ビットアーキテクチャになります.
    p32(113626824, endian='little')
    # and
    p32(113626828, endian='little')
    
    以下はexploitです.
    from pwn import *
    
    payload = p32(113626824, endian='little') * 4 + p32(113626828, endian='little')
    p = process(['./col', payload])
    ret = p.recvline()
    print(ret)
    
    なぜプロセスへの呼び出し前にペイロード?ペイロードをコマンドライン引数として渡す必要があるからです.
    なぜ全体の計算だけでなく、結果?なぜなら、20バイトのペイロードが必要だからです.我々は、命令だけでなく、結果を通過している.方法の詳細は、なぜ私に少し不明瞭です.私は2、3の試みをしました、そして、これは結局は働きました.
    ~/.../pwnable.kr/2 >>> python boum.py                                                                                        
    [+] Starting local process './col': pid 99792
    b'/bin/cat: flag: No such file or directory\n'
    
    そして、それはpwnedです!あなたがそれを楽しんだ希望!