pwn文字列フォーマット脆弱性02-スタックの内容を上書き

4150 ワード

1.1概略方向
スタックとメモリを変更してプログラムの実行フローをハイジャックし、%n変換インジケータは、現在ストリームに正常に書き込まれているバッファの文字列個数をパラメータで指定された整数に格納します.
1.2引き続きフラワーハローワールド
#include 
int main()
{
        int i;
        char str[] = "hello";

        printf("%s %n
",str,&i); printf("%d
",i); }

実行:
root@MSI:/mnt/c/Users/13013/Desktop/PWN/pwn         /02-      # ./example
hello
6

1.3
  • 解析:ここでのiには初期値は付加されていないが、出力は6
  • である.
  • 理由:変換インジケータの前に6文字(スペースを含む)の文字(h e l l o')が書き込まれ、長さ修飾がない場合、デフォルトでintタイプの値が書き込まれます.
  • 1.4一般利用状況:
    通常、上書きする値はshellcodeのアドレスであり、このアドレスは大きな数字であることが多い.この場合、特定の幅または精度の変換仕様を使用して、フォーマット文字列に10進数の整数を加算して出力の最小ビット数を表し、実際のビット数が定義の幅より大きい場合は実際のビット数で出力し、逆にスペースまたは0で補正する必要があります.
    just like this:
    #include 
    int main()
    {
            int i;
            printf("%10u%n
    ",1,&i); printf("%d
    ",i); printf("%.50u%n
    ",1,&i); printf("%d
    ",i); printf("%0100u%n
    ",1,&i); printf("%d
    ",i); }

    実行結果:
    root@MSI:/mnt/c/Users/13013/Desktop/PWN/pwn         /02-      # ./shellcode
             1
    10
    00000000000000000000000000000000000000000000000001
    50
    0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001
    100
    

    よく考えてみると、メモリメモにアドレスを書き込むことができます.
  • 64ビットでは、RDIがフォーマット文字列を渡すために使用されるため、パラメータを書き換えることはできません.
  • 形式文字列(「aa%15$na」)このように、必ず8バイトを
  • に揃えます.
    2.パラメータ位置の計算について
    (変更するアドレス-入力するアドレス)/8+gdbでのオフセット=パラメータ位置
    ここはついでにcanryが参考題を迂回することができます:攻防の世界Mary_Morton(ASIS-TF-FInals-2017)WP:(推奨)Mary Morton wp WPの説明の比較的詳しい
    3.pwntoolsの関連ツール:
    3.1pwntools pwnlib.fmtstr
    1-自動化された文字列脆弱性の利用:
    class pwnlib.fmtstr.FmtStr(execute_fmt, offset=None, padlen=0, n umbwritten=0)
  • excute_fmt(funtion):脆弱性プロセスとインタラクティブ
  • offset(int):あなたが制御する最初のプログラムのオフセット量
  • padlen(int):payloadの前にpadサイズ
  • を追加
  • numbwritten(int):書き込みバイト数
  • 2-payloadの自動生成
    pwnlib.fmtstr.fmtstr_payload(offset, writes, numbwritten=0, writ e_size='byte')
  • offset(int):あなたが制御する最初のフォーマットプログラムのオフセット量
  • writes(dict):フォーマット{addr:value,addr 2:value 2}、addrにvalueの値を書き込むための
  • numbwritten(int):printf関数によって書き込まれたバイト数
  • write_size(str):byte、shortまたはintでなければなりません.byte単位で書くかshort単位で書くかint単位で書くか(hhn,hnまたはn)
  • ========================
    3.2直接問題を出す
    3.2.1ソース:
    #include
    int main()
    {
            char str[1024];
            while(1)
            {
                    memset(str,'\0',1024);
                    read(0,str,1024);
                    printf(str);
                    fflush(stdout);
            }
    }
    

    3.2.2一般的な方法:
    root@MSI:/mnt/c/Users/13013/Desktop/PWN/pwn         /02-      # rabin2 -I fmt
    arch     x86
    baddr    0x400000
    binsz    6814
    bintype  elf
    bits     64
    canary   false
    class    ELF64
    compiler GCC: (Ubuntu 5.4.0-6ubuntu1~16.04.11) 5.4.0 20160609
    crypto   false
    endian   little
    havecode true
    intrp    /lib64/ld-linux-x86-64.so.2
    laddr    0x0
    lang     c
    linenum  true
    lsyms    true
    machine  AMD x86-64 architecture
    maxopsz  16
    minopsz  1
    nx       true
    os       linux
    pcalign  0
    pic      false
    relocs   true
    relro    partial
    rpath    NONE
    sanitiz  false
    static   false
    stripped false
    subsys   linux
    va       true
    

    3.2.3考え方:
    printf()関数のアドレスをsystem()関数のアドレスに変更することで,/bin/shを再入力するとshellが得られると考えられる.
    ====================================
    4.1 CVE-2012-0809
    公式解釈EXP構想は後でCVEの合集で更新しましょう
    4.2補足
    文字列関数のフォーマット
    一般的なフォーマット文字列関数は
  • 入力
  • scanf

  • 出力
  • 関数#カンスウ#
    基本的な紹介
    printf
    stdoutに出力
    fprintf
    指定されたFILEストリームに出力
    vprintf
    パラメータリストに基づいてstdoutにフォーマット出力
    vfprintf
    パラメータリストに従って指定されたFILEストリームにフォーマット出力
    sprintf
    文字列に出力
    snprintf
    指定したバイト数を文字列に出力
    vsprintf
    パラメータリストに基づいて文字列にフォーマット出力
    vsnprintf
    パラメータリストに基づいて出力をフォーマットして文字列にバイトを指定
    setproctitle
    argvの設定
    syslog
    出力ログ
    Err,verr,warn,vwarnなど
    ...
    --------ctfwikiから