📄 157.htm
字号:
fprintf( stderr, "-%02X", byteArray[i] ); <br>
} <br>
else <br>
{ <br>
{ <br>
fprintf( stderr, " %02X", byteArray[i] ); <br>
} <br>
} <br>
fprintf( stderr, " " ); <br>
i -= 16; <br>
for ( j = 0; j < 16; j++, i++ ) <br>
{ <br>
/* if ( isprint( (int)byteArray[i] ) ) */ <br>
if ( ( byteArray[i] >= ' ' ) && ( byteArray[i] <= 255 ) ) <br>
{ <br>
fprintf( stderr, "%c", byteArray[i] ); <br>
} <br>
else <br>
{ <br>
fprintf( stderr, "." ); <br>
} <br>
} <br>
fprintf( stderr, "\n" ); <br>
} /* end of for */ <br>
k = byteArrayLen - i; <br>
if ( k <= 0 ) <br>
{ <br>
{ <br>
return; <br>
} <br>
fprintf( stderr, "%08X ", offset ); <br>
for ( j = 0 ; j < k; j++, i++ ) <br>
{ <br>
if ( j == 8 ) <br>
{ <br>
fprintf( stderr, "-%02X", byteArray[i] ); <br>
} <br>
else <br>
{ <br>
fprintf( stderr, " %02X", byteArray[i] ); <br>
} <br>
} <br>
i -= k; <br>
for ( j = 16 - k; j > 0; j-- ) <br>
{ <br>
fprintf( stderr, " " ); <br>
} <br>
fprintf( stderr, " " ); <br>
for ( j = 0; j < k; j++, i++ ) <br>
{ <br>
{ <br>
if ( ( byteArray[i] >= ' ' ) && ( byteArray[i] <= 255 ) ) <br>
{ <br>
fprintf( stderr, "%c", byteArray[i] ); <br>
} <br>
else <br>
{ <br>
fprintf( stderr, "." ); <br>
} <br>
} <br>
fprintf( stderr, "\n" ); <br>
return; <br>
} /* end of outputBinary */ <br>
int Socket ( int family, int type, int protocol ) <br>
{ <br>
int n; <br>
if ( ( n = socket( family, type, protocol ) ) < 0 ) <br>
{ <br>
perror( "socket" ); <br>
exit( FAILURE ); <br>
} <br>
return( n ); <br>
} /* end of Socket */ <br>
int main ( int argc, char * argv[] ) <br>
{ <br>
recvSocket = Socket( AF_INET, SOCK_RAW, IPPROTO_ICMP ); <br>
while ( 1 ) <br>
{ <br>
memset( packet, 0, 1500 ); <br>
outputBinary( packet, recvfrom( recvSocket, packet, 1500, 0, NULL, N <br>
ULL <br>
) ); <br>
} <br>
Close( recvSocket ); <br>
exit( SUCCESS ); <br>
} /* end of main */ <br>
-------------------------------------------------------------------------- <br>
<br>
可以参考阅读Phrack49-6、Phrack51-6两篇文章。 <br>
<br>
上面的raw.c可以用于测试,现在简单讨论一下要实现的功能。一个rs和rc,rs接收 <br>
icmp echo request报文,从icmp数据区提取有效数据。icmp数据区可能需要自定义 <br>
格式(暂时不考虑加密传输的问题)。比如rs最后得到的指示是要做ls -la操作,那么 <br>
rs应该fork/exec执行/bin/sh -c "ls -la"这个命令。可能涉及到无名管道的技术。 <br>
rs将最终shell命令执行输出利用icmp echo reply负载发送到rc。rc负责接收用户输 <br>
入并利用icmp echo request负载发送到rs,还接收来自rs的icmp echo reply并提取 <br>
有效数据输出到标准输出。简单地、概括地讲,icmp pad backdoor就是这样的。具 <br>
体实现中可能有变化,核心部分不变,那就是利用icmp pad交换数据。 <br>
<br>
另外有个想法,就是利用icmp pad建立一个通道,server host上运行一个daemon, <br>
client host上也运行一个daemon,假设server host位于firewall一侧,client <br>
host位于firewall另一侧。client创建一个tcp socket,监听7704端口, <br>
telnet client 7704,一切输入都被放入icmp pad,client向server发送icmp报文。 <br>
server创建一个tcp socket,连接到本机23端口。server接收icmp报文,提取icmp <br>
pad数据,发送到本机23端口。一切来自本机telnetd的数据都被放入icmp pad, <br>
server向client发送icmp报文。client接收icmp报文,提取icmp pad,从本机7704端 <br>
口上建立的连接发送出去,实际就是返回给最终用户。 <br>
<br>
| <br>
user telnet 7704 | telnetd(23) <br>
| | | <br>
| | | <br>
client host ---------- firewall ---------- server host <br>
listen 7704 允许icmp进出 connect 23 <br>
| | | <br>
| | | <br>
------------------- icmp tunnel ---------------- <br>
| <br>
| <br>
<br>
防火墙设置了很多过滤规则,比如只允许http、icmp通过,此时上述icmp tunnel很 <br>
好用,可以根据不同需要修改server host上connect的目标端口。可以根据不同需要 <br>
安置client/server。client host总是代表最终用户可以直接访问的那一侧。 <br>
如果既要突破防火墙过滤规则,又要保证server host上的隐蔽性,至少不能被 <br>
netstat看出异常,上述icmp tunnel实现就需要修改。 <br>
<br>
client --> server的时候使用icmp echo reply效果比较好。有些Linux可能做了设 <br>
置,不处理icmp echo request,但是icmp echo reply可以在没有出现过icmp echo <br>
request的情况下被发送被接收,而且也更容易突破防火墙。也可以不使用icmp echo, <br>
<br>
但效果可能都不如icmp echo reply。server --> client的时候使用icmp echo <br>
request效果比较好,还是从突破防火墙角度考虑。暂时先这样考虑,以后实在不行 <br>
就提供参数设置。 <br>
<br>
在SPARC/Solaris 2.6下man p2open看看,Linux下没有这个函数。编译的时候需要指 <br>
定-lgen开关。如果要在Linux实现同样功能,可能需要自己pipe、fork、dup2然后 <br>
exec? <br>
<br>
根据p2open的man手册,应该没有重定向标准错误输出,既然如此,还是采用pipe方 <br>
式好些,可能将来移植方便吧。 <br>
<br>
socket( AF_INET, SOCK_RAW, IPPROTO_ICMP )这种套接字,接收的时候对应整个IP <br>
报文,可以读取也必须读取整个IP报文,包括IP头;发送的时候如果没有额外设置 <br>
IP_HDRINCL选项,就不能干涉IP头部数据,sendto()参数中的指针指向ICMP数据区, <br>
而不是IP头,内核会构造IP头。 <br>
<br>
ICMP报文头部的校验和包括ICMP数据区,也就是说对应整个ICMP报文。 <br>
因为使用到无名管道,应该处理SIGPIPE信号。很多问题靠man手册和例子代码是无法 <br>
理解的。一定要从实际编程、调试中才能找到问题、解决问题。这次的 <br>
raw_socket_server.c里处理SIGPIPE信号的技术比较典型,虽然不是最好的解决办法, <br>
但对于我们企图达到的效果足够了。首先设置忽略该信号,然后在write的返回值处 <br>
进行errno判断,如果EPIPE,就认为远程shell已经终止,此时我们关闭以前建立的 <br>
所有管道,重新创建新的管道,重新fork/exec出远程shell,这个远程shell的标准 <br>
输入/输出/错误输出都重定向过了。目前要尽量保持client/server均处在"无状态" <br>
中,避免操作的前后依赖性,否则很多地方处理复杂化。 <br>
<br>
7.12注:上述这个设计文档的实战例子已经可用,所有提到的猜测和技术问题都得到 <br>
实践验证,所以,如果你要写自己的icmp tunnel,可以开工了。上面没有 <br>
提到的就是需要加密传输、口令验证。 <br>
<待续> <br>
-- <br>
</small><hr>
<p align="center">[<a href="index.htm">回到开始</a>][<a href="8.htm">上一层</a>][<a href="158.htm">下一篇</a>]
<p align="center"><a href="http://cterm.163.net">欢迎访问Cterm主页</a></p>
</table>
</body>
</html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -