安全漏洞本質扯談之決戰彙編程式碼
0x00 前言
當前比較流行也比較有效率的挖掘的漏洞的方法是Fuzzing,當然這也需要花點時間去寫Fuzzing程式。然而不是每個東西都有必要去寫Fuzzing程式,也不是每個東西都可以去Fuzzing的,所以也還是要繼續修煉我們的二進位制安全流派內功—“肉眼挖洞神功”。
安全漏洞在原始碼層面和彙編程式碼層面會有不同的表現,想要進階升級的話,必須清晰的瞭解每種安全漏洞型別在原始碼層面和彙編程式碼層面都是張什麼樣的。有些安全漏洞在原始碼層面容易發現它,有些安全漏洞則在彙編程式碼層面比較容易發現它。不管是原始碼層面還是彙編程式碼層面,普通人看程式碼的時候即使看到有安全漏洞的那些程式碼的時候,往往是“只見程式碼,不見漏洞”。修煉“肉眼挖洞神功”的目標是看到那些疑似有問題的程式碼時候能夠警覺,能夠識別,並快速判定是否可形成安全漏洞。
早些時候給我們翰海源的小夥伴們講過《深入安全漏洞-Root Cause of Vulnerabilities》和《決戰彙編程式碼》,希望小夥伴們能夠掌握安全漏洞的本質原因以及練就“肉眼挖洞神功”。今天把裡面的部分例子跟大夥一起分享下。
0x01 原始碼層面
1. Link Attack
*unix 下的 link attack,有意識到嗎?
#!c
if(access("file",W_OK)!=0){
exit(1);
}
fd = open("file",O_WRONLY);
write(fd,buffer,sizeof(buffer));
2. Integer Overflow Example in OpenSSH 3.1
發生在真實的 openssh 3.1 ,有漏洞嗎?
#!c
u_int nresp;
...
nresp = packet_get_int();
if(nresp){
response = xmalloc(nresp * sizeof(char*));
for(i=0; i<nresp; i++)
response[i] = packet_get_string(NULL);
}
packet_check_eom();
3. Signed Integer Vulnerability Example
注意整形符號,能被繞過嗎?
#!c
int read_user_data(int sockfd)
{
int length, sockfd, n;
char buffer[1024];
length = get_user_length(sockfd);
if(length > 1024){
error("illegal input, not enough room in buffer\n");
return 1;
}
if(read(sockfd, buffer, length) < 0){ error("read: %m");
return 1;
}
return 0;
}
4. Truncation Vulnerability Example in NFS
整形截斷問題?
#!c
void assume_privs(unsigned short uid) {
seteuid(uid);
setuid(uid);
}
int become_user(int uid)
{
if (uid == 0)
die("root isnt allowed");
assume_privs(uid);
}
5. 蘋果SSL/TLS 重大安全漏洞的細節
(CVE-2014-1266)多個goto fail造成重大安全隱患。
#!c
static OSStatus
SSLVerifySignedServerKeyExchange(SSLContext *ctx, bool isRsa, SSLBuffer signedParams,
uint8_t *signature, UInt16 signatureLen)
{
...
if ((err = ReadyHash(&SSLHashSHA1, &hashCtx)) != 0)
goto fail;
if ((err = SSLHashSHA1.update(&hashCtx, &clientRandom)) != 0)
goto fail;
if ((err = SSLHashSHA1.update(&hashCtx, &serverRandom)) != 0)
goto fail;
if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != 0)
goto fail;
goto fail; <---- *** DANGER ***
if ((err = SSLHashSHA1.final(&hashCtx, &hashOut)) != 0)
goto fail;
err = sslRawVerify(ctx,
ctx->peerPubKey,
dataToSign, /* plaintext */
dataToSignLen, /* plaintext length */
signature,
signatureLen);
...
fail:
SSLFreeBuffer(&signedHashes);
SSLFreeBuffer(&hashCtx);
return err;
}
6. MS-RPC DCOM Buffer Overflow (衝擊波)
衝擊波蠕蟲只因為一個緩衝區溢位。
#!c
HRESULT GetMachineName (WCHAR * pwszPath) {
The WCHAR wszMachineName [N + 1]);
...
LPWSTR pwszServerName = wszMachineName;
while (* pwszPath! = L '\\')
* PwszServerName + + = * pwszPath + +;
...
}
7. 有漏洞嗎?
#!c
unsigned short read_length(int sockfd)
{
unsigned short len;
if(full_read(sockfd, (void *)&len, 2) != 2)
die("could not read length!\n");
return ntohs(len);
}
int read_packet(int sockfd)
{
struct header hdr;
short length;
char *buffer;
length = read_length(sockfd);
if(length > 1024){
error("read_packet: length too large: %d\n", length);
return 1;
}
buffer = (char *)malloc(length+1);
if((n = read(sockfd, buffer, length) < 0){
error("read: %m");
free(buffer);
return 1;
}
buffer[n] = '\0';
return 0;
}
8. 有漏洞嗎?
提示: 5rOo5oSPc216ZW9m
#!c
char *read_username(int sockfd)
{
char *buffer, *style, userstring[1024];
int i;
buffer = (char *)malloc(1024);
if(!buffer){
error("buffer allocation failed: %m");
return NULL;
}
if(read(sockfd, userstring, sizeof(userstring)-1) <= 0){
free(buffer);
error("read failure: %m");
return NULL;
}
userstring[sizeof(userstring)-1] = '\0';
style = strchr(userstring, ':');
if(style)
*style++ = '\0';
sprintf(buffer, "username=%.32s", userstring);
if(style)
snprintf(buffer, sizeof(buffer)-strlen(buffer)-1,
", style=%s\n", style);
return buffer;
}
9. 有漏洞嗎?
提示:
#!c
/* special thing for ldap.
* The parts are separated by question marks.
* From RFC 2255:
* ldapurl = scheme "://" [hostport] ["/"
* [dn ["?" [attributes] ["?" [scope]
* ["?" [filter] ["?" extensions]]]]]]
*/
if (!strncasecmp(uri, "ldap", 4))
{
char *token[5];
int c = 0;
token[0] = cp = ap_pstrdup(p, cp);
while (*cp && c < 5) {
if (*cp == '?') {
token[++c] = cp + 1;
*cp = '\0';
}
++cp;
}
10. 有漏洞嗎?(Antisniff v1.1 Vulnerability)
tips
#!c
char *indx;
int count;
char nameStr[MAX_LEN]; //256
...
memset(nameStr, '\0', sizeof(nameStr));
...
indx = (char *)(pkt + rr_offset);
count = (char)*indx;
while (count){
if (strlen(nameStr) + count < ( MAX_LEN - 1) ){
(char *)indx++;
strncat(nameStr, (char *)indx, count);
indx += count;
count = (char)*indx;
strncat(nameStr, ".",
sizeof(nameStr) strlen(nameStr));
} else {
fprintf(stderr, "Alert! Someone is attempting "
"to send LONG DNS packets\n");
count = 0; }
}
nameStr[strlen(nameStr)-1] = '\0';
11. 還有漏洞嗎?(Antisniff v1.1.1 Vulnerability)
#!c
char *indx;
int count;
char nameStr[MAX_LEN]; //256
...
memset(nameStr, '\0', sizeof(nameStr));
...
indx = (char *)(pkt + rr_offset);
count = (char)*indx;
while (count){
/* typecast the strlen so we aren't dependent on
the call to be properly setting to unsigned. */
if ((unsigned int)strlen(nameStr) +
(unsigned int)count < ( MAX_LEN - 1) ){
(char *)indx++;
strncat(nameStr, (char *)indx, count);
indx += count;
count = (char)*indx;
strncat(nameStr, ".",
sizeof(nameStr) strlen(nameStr));
} else {
fprintf(stderr, "Alert! Someone is attempting "
"to send LONG DNS packets\n");
count = 0;
}
}
nameStr[strlen(nameStr)-1] = '\0';
12. 還有漏洞嗎?(Antisniff v1.1.2 Vulnerability)
#!c
unsigned char *indx;
unsigned int count;
unsigned char nameStr[MAX_LEN]; //256
...
memset(nameStr, '\0', sizeof(nameStr));
...
indx = (char *)(pkt + rr_offset);
count = (char)*indx;
while (count){
if (strlen(nameStr) + count < ( MAX_LEN - 1) ){
indx++;
strncat(nameStr, indx, count);
indx += count;
count = *indx;
strncat(nameStr, ".",
sizeof(nameStr) strlen(nameStr));
} else {
fprintf(stderr, "Alert! Someone is attempting "
"to send LONG DNS packets\n");
count = 0;
}
}
nameStr[strlen(nameStr)-1] = '\0';
0x02 彙編程式碼層面
接下要在彙編程式碼堆裡磨練下,下面的彙編程式碼有安全問題嗎?都是些什麼問題?
1. Safe or vulnerability?
#!bash
text:0040106B sub_40106B proc near ; CODE XREF: _main+58p
.text:0040106B
.text:0040106B var_10004 = byte ptr -10004h
.text:0040106B var_4 = dword ptr -4
.text:0040106B arg_0 = word ptr 8
.text:0040106B
.text:0040106B push ebp
.text:0040106C mov ebp, esp
.text:0040106E mov eax, 10004h
.text:00401073 call __alloca_probe
.text:00401078 mov eax, dword_404020
.text:0040107D xor eax, ebp
.text:0040107F mov [ebp+var_4], eax
.text:00401082 movsx eax, [ebp+arg_0]
.text:00401086 movsx eax, [ebp+eax+var_10004]
.text:0040108E push eax
.text:0040108F push offset Format ; "t %x"
.text:00401094 call ds:printf
.text:0040109A pop ecx
.text:0040109B pop ecx
.text:0040109C mov ecx, [ebp+var_4]
.text:0040109F xor ecx, ebp
.text:004010A1 xor eax, eax
.text:004010A3 call sub_401BD2
.text:004010A8 leave
2. Safe or vulnerability?
#!bash
text:004010AA sub_4010AA proc near ; CODE XREF: _main+60p
.text:004010AA
.text:004010AA var_190 = dword ptr -190h
.text:004010AA arg_0 = dword ptr 8
.text:004010AA
.text:004010AA push ebp
.text:004010AB mov ebp, esp
.text:004010AD mov eax, [ebp+arg_0]
.text:004010B0 sub esp, 190h
.text:004010B6 cmp eax, 64h
.text:004010B9 jle short loc_4010BE
.text:004010BB push 64h
.text:004010BD pop eax
.text:004010BE
.text:004010BE loc_4010BE: ; CODE XREF: sub_4010AA+Fj
.text:004010BE push [ebp+eax*4+var_190]
.text:004010C5 push offset Format ; "t %x"
.text:004010CA call ds:printf
.text:004010D0 pop ecx
3. Safe or vulnerability?
#!bash
.text:00401000 sub_401000 proc near ; CODE XREF: _main+48p
.text:00401000
.text:00401000 var_190 = dword ptr -190h
.text:00401000 arg_0 = dword ptr 8
.text:00401000
.text:00401000 push ebp
.text:00401001 mov ebp, esp
.text:00401003 mov eax, [ebp+arg_0]
.text:00401006 sub esp, 190h
.text:0040100C cmp eax, 64h
.text:0040100F jbe short loc_401014
.text:00401011 push 64h
.text:00401013 pop eax
.text:00401014
.text:00401014 loc_401014: ; CODE XREF: sub_401000+Fj
.text:00401014 push [ebp+eax*4+var_190]
.text:0040101B push offset Format ; "t %x"
.text:00401020 call ds:printf
.text:00401026 pop ecx
.text:00401027 pop ecx
4. Safe or vulnerability?
#!bash
.text:004010D6 sub_4010D6 proc near ; CODE XREF: _main+68p
.text:004010D6
.text:004010D6 arg_0 = dword ptr 4
.text:004010D6
.text:004010D6 push esi
.text:004010D7 push 64h ; Size
.text:004010D9 call ds:malloc
.text:004010DF mov esi, eax
.text:004010E1 mov eax, [esp+8+arg_0]
.text:004010E5 cmp eax, 64h
.text:004010E8 pop ecx
.text:004010E9 jle short loc_4010EE
.text:004010EB push 64h
.text:004010ED pop eax
.text:004010EE
.text:004010EE loc_4010EE: ; CODE XREF: sub_4010D6+13j
.text:004010EE movsx eax, byte ptr [eax+esi]
.text:004010F2 push eax
.text:004010F3 push offset Format ; "t %x"
.text:004010F8 call ds:printf
.text:004010FE push esi ; Memory
.text:004010FF call ds:free
5. Safe or vulnerability?
#!bash
. text:0040110C sub_40110C proc near ; CODE XREF: _main+70p
.text:0040110C
.text:0040110C var_19A0 = byte ptr -19A0h
.text:0040110C var_4 = dword ptr -4
.text:0040110C arg_0 = word ptr 8
.text:0040110C
.text:0040110C push ebp
.text:0040110D mov ebp, esp
.text:0040110F mov eax, 19A0h
.text:00401114 call __alloca_probe
.text:00401119 mov eax, dword_404020
.text:0040111E xor eax, ebp
.text:00401120 mov [ebp+var_4], eax
.text:00401123 movsx eax, [ebp+arg_0]
.text:00401127 movsx eax, [ebp+eax+var_19A0]
.text:0040112F push eax
.text:00401130 push offset Format ; "t %x"
.text:00401135 call ds:printf
.text:0040113B pop ecx
.text:0040113C pop ecx
.text:0040113D mov ecx, [ebp+var_4]
.text:00401140 xor ecx, ebp
6. Safe or vulnerability?
#!bash
.text:0040102C sub_40102C proc near ; CODE XREF: _main+50p
.text:0040102C
.text:0040102C var_10004 = byte ptr -10004h
.text:0040102C var_4 = dword ptr -4
.text:0040102C arg_0 = word ptr 8
.text:0040102C
.text:0040102C push ebp
.text:0040102D mov ebp, esp
.text:0040102F mov eax, 10004h
.text:00401034 call __alloca_probe
.text:00401039 mov eax, dword_404020
.text:0040103E xor eax, ebp
.text:00401040 mov [ebp+var_4], eax
.text:00401043 movzx eax, [ebp+arg_0]
.text:00401047 movsx eax, [ebp+eax+var_10004]
.text:0040104F push eax
.text:00401050 push offset Format ; "t %x"
.text:00401055 call ds:printf
.text:0040105B pop ecx
7. Safe or vulnerability?
#!bash
. .text:0040118A ; int __cdecl sub_40118A(LPCSTR lpMultiByteStr)
.text:0040118A sub_40118A proc near ; CODE XREF: _main+91p
.text:0040118A
.text:0040118A WideCharStr = word ptr -44h
.text:0040118A var_4 = dword ptr -4
.text:0040118A lpMultiByteStr = dword ptr 8
.text:0040118A
.text:0040118A push ebp
.text:0040118B mov ebp, esp
.text:0040118D sub esp, 44h
.text:00401190 mov eax, dword_404020
.text:00401195 xor eax, ebp
.text:00401197 mov [ebp+var_4], eax
.text:0040119A mov ecx, [ebp+lpMultiByteStr]
.text:0040119D mov eax, ecx
.text:0040119F push esi
.text:004011A0 lea esi, [eax+1]
.text:004011A3
.text:004011A3 loc_4011A3: ; CODE XREF: sub_40118A+1Ej
.text:004011A3 mov dl, [eax]
.text:004011A5 inc eax
.text:004011A6 test dl, dl
.text:004011A8 jnz short loc_4011A3
.text:004011AA push 40h ; cchWideChar
.text:004011AC lea edx, [ebp+WideCharStr]
.text:004011AF push edx ; lpWideCharStr
.text:004011B0 sub eax, esi
.text:004011B2 push eax ; cbMultiByte
.text:004011B3 push ecx ; lpMultiByteStr
.text:004011B4 push 0 ; dwFlags
.text:004011B6 push 0 ; CodePage
.text:004011B8 call ds:MultiByteToWideChar
8. Safe or vulnerability?
#!bash
text:00401738 Size = dword ptr 4
.text:00401738 Src = dword ptr 8
.text:00401738
.text:00401738 push esi
.text:00401739 push edi
.text:0040173A mov edi, [esp+8+Size]
.text:0040173E lea eax, [edi+1]
.text:00401741 push eax ; Size
.text:00401742 call ds:__imp__malloc
.text:00401748 mov esi, eax
.text:0040174A test esi, esi
.text:0040174C pop ecx
.text:0040174D jz short loc_401774
.text:0040174F push edi ; Size
.text:00401750 push [esp+0Ch+Src] ; Src
.text:00401754 push esi ; Dst
.text:00401755 call _memcpy
.text:0040175A push esi
.text:0040175B push offset aS ; "%s\n"
.text:00401760 mov byte ptr [esi+edi], 0
.text:00401764 call ds:__imp__printf
0x04 最後
彙編程式碼層面的例子需要想想它們的原始碼都是怎麼寫的才能編譯出來這些有安全漏洞的程式碼。做到原始碼層面和彙編程式碼層面通吃。更要做到從宏觀上了解程式世界功能和規則,從微觀上了解其實現細節。
上面的例子都不到一百行的彙編程式碼,都找出問題了嗎?決戰彙編程式碼就是需要我們在真實程式世界的上千萬行彙編程式碼中找出那些隱藏的安全漏洞,這個難度會高很多。其中有對抗有程式設計者的防禦措施,需要思考如何打敗它,是和程式世界的締造者們的一次跨時間和空間無聲的較量。
以上這些其實是一個引子,需要小夥伴繼續深入研究推演和鍛鍊。推薦學習Mark Down & JohnMcDonald兩位大牛的書《The Art of Software Security Assessment-- Identifying andavoiding software vulnerabilities》(某些例子來自該書),希望對小夥伴們有所幫助。
相關文章
- 彙編程式碼Helloworld2018-03-22
- 深入iOS系統底層之程式中的彙編程式碼2019-02-18iOS
- CatFly【彙編程式碼還原】2023-12-22
- 談談一個程式設計師本該具備的素質2018-12-15程式設計師
- iOS彙編入門教程(二)在Xcode工程中嵌入彙編程式碼2018-03-23iOSXCode
- 植物大戰殭屍,用QT注入程式碼,AT&T彙編語法2024-03-08QT
- 閒談團隊的程式碼質量2019-03-01
- 🐒編寫高質量程式碼(手撕程式碼)2024-11-07
- Java程式碼如何檢視位元組碼及彙編碼2021-01-25Java
- 淺談RASP技術攻防之實戰[程式碼實現篇]2019-05-08
- react之JSX本質2020-09-23ReactJS
- x86彙編之棧與子程式呼叫2020-04-20
- kubebuilder實戰之五:operator編碼2021-08-30UI
- 體面編碼之程式碼提交2018-12-31
- 09. C語言內嵌彙編程式碼2024-05-09C語言
- 計算機執行彙編程式碼的原理2024-09-15計算機
- NEON彙編比純C程式碼快17倍!2022-03-21C程式
- 淺談彙編器、編譯器和直譯器2019-06-26編譯
- 逆向之彙編筆記2020-12-30筆記
- 消除程式碼中的壞味道,編寫高質量程式碼2020-09-13
- 一段C語言和彙編的對應分析,揭示函式呼叫的本質2021-09-09C語言函式
- 【程式設計素質】Java編碼約定2018-09-29程式設計Java
- iOS 彙編基礎(三)還原高階程式碼之迴圈和判斷2018-05-02iOS
- 談談JavaScript編碼風格2019-04-10JavaScript
- windows搭建彙編程式IDE2018-03-31WindowsIDE
- STM彙編程式設計2020-12-30程式設計
- win32下彙編程式碼結構學習2024-05-13Win32
- 學習筆記分享之彙編---2.彙編指令/語法2020-04-18筆記
- iOS 編寫高質量Objective-C程式碼2018-09-19iOSObjectC程式
- Alink漫談(十八) :原始碼解析 之 多列字串編碼MultiStringIndexer2020-08-15原始碼字串編碼Index
- JVM 模板直譯器之如何根據位元組碼生成彙編碼?2021-09-09JVM
- 迪文屏OS彙編程式碼開發-串列埠篇2020-12-19串列埠
- Android安全開發之淺談金鑰硬編碼2020-08-19Android
- Flutter 命令本質之 Flutter tools 機制原始碼深入分析2021-07-25Flutter原始碼
- iOS編寫高質量Objective-C程式碼(六)2018-10-29iOSObjectC程式
- iOS 編寫高質量Objective-C程式碼(七)2018-10-29iOSObjectC程式
- iOS 編寫高質量Objective-C程式碼(八)2018-11-29iOSObjectC程式
- iOS 編寫高質量Objective-C程式碼(六)2018-10-15iOSObjectC程式