socket( PF_INET
SOCK_RAW
IPPROTO_TCP );
在RedHat
下這兩種socket都可以正常建立
內核支持了的
但是對於Solaris
如果以root身份truss跟蹤這兩個函數
發現第二個socket建立的時候 內核不支持這種情況下指定IPPROTO_TCP
庫函數本身做了處理
so_socket(
) Err#
EPROTOTYPE
stat(
/dev/rawip
xEFFFFAC
) =
so_socket(
/dev/rawip
) =
setsockopt(
xEFFFFBB
) =
從執行效果看
這樣的處理和Linux下的意義不同了
如果考慮廣泛兼容性
應該扔棄第二種socket
全部以IPPROTO_RAW方式出現
這樣的話
理論上可以考慮不用TCP/UDP協議
但是涉及client/server模式
顯然應該繼
續使用TCP/UDP
從突破防火牆角度看
還是以鬼子的ACK方式為好
UDP通信被很多防火牆屏蔽
TCP也好不到哪裡去
而且按照目前的設想
等於僅僅使用TCP的頭部概 念
並沒有使用TCP協議的超時
重傳等機制
更沒有有限狀態機介入
為什麼不使用UDP呢?還是應該從防火牆角度考慮這個設計選擇
具體問題具體分析吧
現在的難點是完全使用IPPROTO_RAW
寫沒多大問題
讀有了麻煩
又需要重翻UNP
此外
丟包是毫無疑問的
因此必須盡量設計成無狀態方式(NFS Server就是一個例子)
這 個也僅僅是說說
技術問題尚未可知
關於內核傳遞IP報文到一個raw_socket
有幾點需要注意
我們分別探討之
) TCP/UDP報文(IP報文負載為TCP/UDP)
永遠
不會傳遞給raw_socket
Stevens介紹
的時候以BSD家族為例
對於Linux顯然已經不適用這個結論
socket( PF_INET
SOCK_RAW
IPPROTO_TCP )
就可以接收到TCP報文
Linux內核是給了這個機會的
此時正常的TCP協議層也會收到TCP報文(後面我們會寫測試代碼驗證它)
於是造成潛在的安全隱患
在無需
數據鏈路層和網卡混雜模式介入的情況下
利用raw_socket監視發往本機的TCP報文
盡管只有root才可以創建raw_socket
但獲得創建raw_socket的機會和獲得完整root權限相比要大得多
對於Solaris系統
內核應該是沒有支持
socket( PF_INET
SOCK_RAW
IPPROTO_TCP )方式
盡管以root身份執行庫函數並沒有報錯(此時庫函數自己做了其他處理)
對於Windows
K
從backend拖回來的程序執行效果以及袁哥分析代碼的結論看
K可能支持socket( PF_INET
SOCK_RAW
IPPROTO_TCP )這種方式
抓包分析
backdoor的client/server通信
發現除了預料中的ACK
還夾帶有RST
只能說明
K內核傳遞IP報文到raw_socket的同時傳遞給了正常的TCP協議層
RST是由正常
TCP協議層發出的
NT/
x估計沒戲
考慮我們要達到的目的
如果內核不給這個機會(傳遞TCP報文到raw_socket)
意味著ACK方式破產
UDP自然也不用想了
雖然Linux可以
但我們希望得到一個更廣泛兼容的backdoor
可以從數據鏈路層考慮這個問題
牽扯的問題更多
沒有太大必要
) 對於伯克利實現而言
內核一般處理了幾種常見ICMP報文(
種
回應請求
時間戳請求
地址掩碼請求)
其余未處理ICMP報文交給raw_socket
注意內核並沒有
處理上面三種請求報文的應答報文
想想ping
c的實現
如果內核處理icmp echo reply
即使指定IPPROTO_ICMP
處於應用層的ping也沒有機會得到應答報文
這裡所說內核處理
都是指處理入IP報文
對於發送IP報文
基本上任
由應用程序處理的
所以ping可以發送自己的icmp echo request
Linux/Solaris的實現有差別
提供給應用層更多機會
內核處理了icmp echo request
同時會交給socket( PF_INET
SOCK_RAW
IPPROTO_ICMP )
不同於BSD
實現
內核未處理的icmp報文依舊交給raw_socket
這給我們一個機會
編寫自己的icmp daemon
利用被內核傳遞到raw_socket的icmp報文進行交互式通信
從突破防火牆角度考慮
比較現實
一般管理員會允許icmp echo request進入
管理員要是在防火牆上過濾了icmp echo request
估計我們也沒有機會在這種敵人內部安裝icmp daemon
走先
) 所有的IGMP報文交給raw_socket
同上
可以利用
現在的操作系統好象已經開始在內核裡處理igmp
那樣的話
機會不大
而且防火牆對IGMP報文比較敏感
socket( AF_INET
SOCK_RAW
IPPROTO_IGMP )
Linux上可以接收到IGMP報文
Solaris上不行
) 如果內核無法理解IP報文頭中高層協議類型
傳遞該報文給raw_socket
內核無法理解的
對於防火牆也是無法理解的
除非不考慮突破防火牆的網絡拓撲
否則暫時別想
此外從前面的測試中看到
Linux/Solaris下必須精確指定第
三個參數可以接收匹配IP報文
如果要利用內核無法理解之協議類型
必須確保該類型可以指定在第三個參數中
) IP分片一定是在內核中重組完成了才會傳遞給raw_socket
換句話說
raw_socket無法分析IP分片
數據鏈路層可以
這裡隱含著一個意思
IP分片重組永遠在內核完成
一旦這部分的處理代碼出了問題
就是內核的麻煩
所以死得快
) 如果內核決定傳遞一個IP報文到raw_socket
則系統中所有進程創建的所有raw_socket都會收到這個IP報文
這是一個潛在的安全問題
我們在測試程序中創建socket( PF_INET
SOCK_RAW
IPPROTO_ICMP )
啟動了兩
個實例
然後從其他主機ping本機
兩個實例都收到了icmp echo request
) 創建socket( PF_INET
SOCK_RAW
)
並且不調用bind
connect
這樣的
raw_socket接收所有內核傳遞上來的IP報文
第三個參數是指定匹配的
如果非
零
不匹配的IP報文不會被傳遞給該raw_socket
對於這種系統
企圖監視本機
所有入IP報文
不需要數據鏈路層介入
也不要求網卡混雜模式
簡單創建一個
raw_socket
指定第三個參數為
即可
遺憾的是
我們在Linux下測試
根本就不支持第三個參數指定為
指定成
(IPPROTO_RAW)也無法達到Stevens描述的效果
主要用於發送
Stevens介
紹的可能僅僅是BSD實現吧
關於這個
覺得看看Linux關於raw_socket的實現部分比較好
瞎猜也不是辦法
) 有些代碼使用了raw_socket
並未指定IP_HDRINCL選項
年為了解決
traceroute問題引入了一個patch
創建SOCK_RAW時
指定第三個參數為
IPPROTO_RAW(值
)
效果和指定IP_HDRINCL選項一樣
還更方便些
/*
* For Solaris
* gcc
O
o raw raw
c
lsocket
lnsl
*
* For Linux
* gcc
O
o raw raw
c
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define SUCCESS
#define FAILURE
int recvSocket;
u_char packet[
];
void Close ( int fd )
{
if ( close( fd ) ==
)
{
perror(
close
);
exit( FAILURE );
}
return;
} /* end of Close */
void outputBinary ( const unsigned char * byteArray
const size_t byteArrayLen )
{
u_long offset;
int i
j
k;
fprintf( stderr
byteArray [ %lu bytes ]
> \n
byteArrayLen );
if ( byteArrayLen <=
)
{
return;
}
i =
;
offset =
;
for ( k = byteArrayLen /
; k >
; k
offset +=
)
{
fprintf( stderr
%
X
offset );
for ( j =
; j <
; j++
i++ )
{
if ( j ==
)
{
fprintf( stderr
%
X
byteArray[i] );
}
else
{
fprintf( stderr
%
X
byteArray[i] );
}
}
fprintf( stderr
);
i
=
;
for ( j =
; j < 16; j++, i++ )
{
/* if ( isprint( (int)byteArray[i] ) ) */
if ( ( byteArray[i] >=
) && ( byteArray[i] <= 255 ) )
{
fprintf( stderr, "%c", byteArray[i] );
}
else
{
fprintf( stderr, "." );
}
}
fprintf( stderr, "\n" );
} /* end of for */
k = byteArrayLen - i;
if ( k <= 0 )
{
return;
}
fprintf( stderr, "%08X ", offset );
for ( j = 0 ; j < k; j++, i++ )
{
if ( j == 8 )
{
fprintf( stderr, "-%02X", byteArray[i] );
}
else
{
fprintf( stderr, " %02X", byteArray[i] );
}
}
i -= k;
for ( j = 16 - k; j > 0; j-- )
{
fprintf( stderr, " " );
}
fprintf( stderr, " " );
for ( j = 0; j < k; j++, i++ )
{
if ( ( byteArray[i] >= ' ' ) && ( byteArray[i] <= 255
From:http://tw.wingwit.com/Article/program/Oracle/201311/17939.html