通行证│用户名: 密码: 验证码: 验证码,看不清楚?请点击刷新验证码 电信网通铁通移动   在线
文章搜索:
热门搜索:红客 黑鹰 红客技术 安全动画 红客培训
首页 文章 软件 动画 资源 励志 论坛 邮箱 会员 军事 科技 博客 爱心红客 最近更新 800g资源
 业内新闻 漏洞公告 病毒公告 电脑知识 网络知识 菜鸟入门 攻防教程 黑客攻防 安全编程 工具使用 综合安全 个人安全 安全相关 Q Q安全 原创精华 红客人物 站内事件
您现在的位置: 爱国者安全网 >> 文章类 >> 红客教程 >> 网络攻防 >> 文章正文
入侵技术介绍——目标探测(2)
责任编辑:admin   更新日期:2005-7-6
 
 计划介绍的内容包括信息收集,探测,渗透,帐号破解,入侵攻击,清除踪迹,后门制作等等(庞大的计划),主要都是从实现上来讲的(使用其他工具的不是计划内),其中的代码都需要自己写。不过我时间有限,写一次需要很长时间,也许一段时间内没时间写。那也怪不得我哦。不过,只希望能够让更多人脱离“工具黑客”,去看看实际到底是什么,然后去自己探索应该是什么。

写这个的目的不是教人怎么入侵怎么“黑”,只是让更多人去学习,去研究。

欢迎交流,Email: refdom@263.net

声明:所有都是属于一种技术上的研究和探讨,如果有人利用下面涉及的技术进行破坏等,与本人无任何关系!
************************************************************************



          2、目标探测

作者: Refdom,
EmaiL: Refdom@263.net
2002/1/17

  确定目标并收集相关的周边信息之后,更直接地要接触目标的手段的就是进行探测了。探测一台主机包括是否活动、主机系统、正在使用哪些端口、提供了哪些服务、相关服务的软件版本等等
  对这些内容的探测就是为了“对症下药”。

  探测也就是大家所说的扫描,应该说扫描是最多使用工具的一个步骤,现在扫描工具也非常的多,从一般的Port Scanner到可以穿透防火墙的Scan 工具,比如强大的nmap,国内的X-Scanner、流光等等。在这里,我不是来介绍工具使用的,而主要是看看这些扫描工具到底是怎么来实现的。如果你喜欢上一个工具的话,也就表示你丧失了一次进步的机会。
  这里都是一些简单的小程序,功能非常有限,只是为了说明实现原理而写的。有兴趣的可以自己做更广泛的修改,而实现更多的功能。

  ICMP协议——PING是最常用的,也是最简单的探测手段,用来判断目标是否活动。实际上Ping是向目标发送一个要求回显(Type = 8)的ICMP数据报,当主机得到请求后,再返回一个回显(Type = 0)数据报。而且Ping 程序一般是直接实现在系统内核中的,而不是一个用户进程。我们也可以很容易实现一个Ping程序,这里我列出我写的一个简单Ping程序。

#include
#include

typedef struct ip_hdr //定义IP首部
{
unsigned char h_verlen; //4位首部长度,4位IP版本号
unsigned char tos; //8位服务类型TOS
unsigned short total_len; //16位总长度(字节)
unsigned short ident; //16位标识
unsigned short frag_and_flags; //3位标志位
unsigned char ttl; //8位生存时间 TTL
unsigned char proto; //8位协议 (TCP, UDP 或其他)
unsigned short checksum; //16位IP首部校验和
unsigned int sourceIP; //32位源IP地址
unsigned int destIP; //32位目的IP地址
}IP_HEADER;

typedef struct icmp_hdr
{
BYTE i_type; // ICMP报文类型
BYTE i_code;     // ICMP代码
USHORT i_cksum; // 校验和
USHORT i_id; // 标志符
USHORT i_seq; // 序号
ULONG timestamp; // 时间戳
} ICMP_HEADER;

//CheckSum:计算校验和的子函数
USHORT checksum(USHORT *buffer, int size)
{
unsigned long cksum=0;
while(size >1)
{
cksum+=*buffer++;
size -=sizeof(USHORT);
}
if(size )
{
cksum += *(UCHAR*)buffer;
}
cksum = (cksum >> 16) + (cksum & 0xffff);
cksum += (cksum >>16);
return (USHORT)(~cksum);
}

void useage()
{
printf("******************************************\n");
printf("ICMPPing\n");
printf("\t Written by Refdom\n");
printf("\t Email: refdom@263.net\n");
printf("Useage: ICMPPing.exe Target_ip \n");
printf("*******************************************\n");
}

void DecodeHeader(char*, int);

void main(int argc, char* argv[])
{
ICMP_HEADER icmpHeader;
int rect;
WSADATA WSAData;
SOCKET sock;
SOCKADDR_IN addr_in,addr_from;
char recvbuf[1024];

useage();
if (argc!=2)
{ exit(0); }

if (WSAStartup(MAKEWORD(2,2), &WSAData) != 0 )
{ printf ("WSAStartup Error!\n");
exit(0);
}

sock= socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
int nTimeOut = 2000;
setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char*)&nTimeOut, sizeof(nTimeOut));
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char*)&nTimeOut, sizeof(nTimeOut));
memset(&addr_in, 0, sizeof(addr_in));
addr_in.sin_family = AF_INET;
addr_in.sin_addr.S_un.S_addr = inet_addr(argv[1]);

if (addr_in.sin_addr.S_un.S_addr == INADDR_NONE)
{
struct hostent *host = NULL;
if ((host = gethostbyname(argv[1])) != NULL)
{
memcpy(&(addr_in.sin_addr), host->h_addr, host->h_length);
}
}
//
memset(&icmpHeader, 0, sizeof(icmpHeader));
icmpHeader.i_type = 8;
icmpHeader.i_code = 0;
icmpHeader.i_cksum = 0;
icmpHeader.i_id = (USHORT)GetCurrentProcessId();
icmpHeader.i_seq = 0;
icmpHeader.timestamp = GetTickCount();
icmpHeader.i_cksum = checksum((USHORT*)&icmpHeader, sizeof(icmpHeader));

rect = sendto(sock, (char*)&icmpHeader, sizeof(icmpHeader), 0, (sockaddr*)&addr_in, sizeof(addr_in));
int addr_from_len;
addr_from_len = sizeof(addr_from);
rect = recvfrom(sock, recvbuf, sizeof(recvbuf), 0, (sockaddr*)&addr_from, &addr_from_len);
DecodeHeader(recvbuf, rect);
closesocket(sock);
WSACleanup();
}

void DecodeHeader(char* buf, int len)
{
ICMP_HEADER *icmpHeader;
IP_HEADER *ipHeader;
IN_ADDR addr;
icmpHeader = (ICMP_HEADER*)(buf+20);
DWORD Time1;

Time1 = GetTickCount();
ipHeader = (IP_HEADER*)malloc(20);
memcpy(ipHeader, buf, 20);
addr.S_un.S_addr = ipHeader->sourceIP;
if (icmpHeader->i_type != 0)
{ printf("No replay!\n"); }
if (icmpHeader->i_id != (USHORT)GetCurrentProcessId())
{ printf("other pocket!\n"); }
printf("Reply from %s: Bytes= %d ", inet_ntoa(addr), len);
printf("TTL = %d Time= %d ms.\n", ipHeader->ttl, Time1-icmpHeader->timestamp );
}
(其中去掉了一些错误判断的地方,呵呵,节约空间)
  PING得到的结果包括字节数、反应时间、以及生存时间。Ping程序通过在ICMP报文数据中存放发送请求的时间来计算返回时间。当应答返回时,根据现在时间减去报文中存放的发送时间就得到反应时间了。生存时间(TTL),本来就存放在IP数据报的头部,直接就能够获取。我们能够根据TTL时间来大致判断目标主机的系统类型,以及我们需要到达目的地需要经过几个路由器等等。
但是普通的Ping命令只能对一台主机进行探测,如果是要判断一个大类的网络是否有哪些活动的机器的话,就需要制作一个用来大面积Ping的工具,当然,你可以改进上面的基本程序,或者使用多线程并发来满足大面积Ping的需要。
  还有一个Tracert 命令,也非常有用,可以参考以前写的,这里就不再罗嗦了。
  关于ICMP协议的其他使用,比如,ICMP拒绝服务攻击等等,以后再讨论。

  由于现在一些防火墙对ICMP进行控制,所以,实际上用ping来做判断已经非常不可靠了。即使是个人防火墙,你也Ping不进去了。
  当然,我们有更多探测的方式,我们可以不使用ICMP协议,而使用更普通的TCP协议来进行探测,而且进行对方开放端口的扫描。普通的TCP探测是直接用connect()进行的,但是,在对方有防火墙情况下,Connect() 探测得出的结果也是不能确信的,如果熟悉更多关于TCP/IP协议的内容,我们就可以通过TCP/IP协议的特点尽可能地绕过防火墙。这就是大家所说得半开式扫描,其原理也就是不直接使用Connect进行对方端口得连接,而是发送TCP的标志位来实现,而且这样根本就不用同目标主机进行实际的连接。
  在X-Scanner也有使用SYN探测的一项,也就是通过下面这些原理来做的。

SYN PING
SYN位表示一个TCP连接的开始,也就是三次握手的第一步,向远端主机某端口发送一个只有SYN标志位的TCP数据报,如果主机反馈一个SYN || ACK数据包,那么,这个主机正在监听该端口,如果反馈的是RST数据包,说明,主机没有监听该端口。

ACK PING
在三次握手中,ACK来表示确认握手过程,但是,如果根本没有进行SYN的请求,而去确认连接,目标主机就会认为一个错误发生了,而发送RST位来中断会话。发送一个只有ACK标志的TCP数据报给主机,如果主机反馈一个TCP RST数据报来,那么这个主机是存在的。ACK探测更容易通过一些 stateless型的防火墙。

FIN ping
因为FIN标志表示一个结束,但是目标主机根本就没有这个连接记录,所以,根据TCP/IP协议,目标主机就要发送一个RST标志的数据包来中断这个会话。对某端口发送一个TCP FIN数据报给远端主机,如果主机没有任何反馈,那么这个主机是存在的,而且正在监听这个端口;主机反馈一个TCP RST回来,那么说明该主机是存在的,但是没有监听这个端口。

NULL Ping
即发送一个没有任何标志位的TCP包,根据RFC793,如果目标主机的相应端口是关闭的话,应该发送回一个RST数据包。

  后两种办法可以绕过一些防火墙,而得到防火墙后面的主机信息。即使在ICMP包被过滤的情况下,一般TCP探测还是能够成功的。当然,是在不被欺骗的情况下的。

  下面这段程序就是一个TCP/IP半开探测的例子,当然,并没有做得完美,因为没有接收部分,而在WIN2000下实际就是一个选择性的SNIFFER,呵呵,大家可以使用其他的SNIFFER来实现同样的目的。

#include
#include
#include

#define SOURCE_PORT 7234
#define MAX_RECEIVEBYTE 255

typedef struct ip_hdr //定义IP首部
{
unsigned char h_verlen; //4位首部长度,4位IP版本号
unsigned char tos; //8位服务类型TOS
unsigned short total_len; //16位总长度(字节)
unsigned short ident; //16位标识
unsigned short frag_and_flags; //3位标志位
unsigned char ttl; //8位生存时间 TTL
unsigned char proto; //8位协议 (TCP, UDP 或其他)
unsigned short checksum; //16位IP首部校验和
unsigned int sourceIP; //32位源IP地址
unsigned int destIP; //32位目的IP地址
}IPHEADER;

typedef struct tsd_hdr //定义TCP伪首部
{
unsigned long saddr; //源地址
unsigned long daddr; //目的地址
char mbz;
char ptcl; //协议类型
unsigned short tcpl; //TCP长度
}PSDHEADER;

typedef struct tcp_hdr //定义TCP首部
{
USHORT th_sport; //16位源端口
USHORT th_dport; //16位目的端口
unsigned int th_seq; //32位序列号
unsigned int th_ack; //32位确认号
unsigned char th_lenres; //4位首部长度/6位保留字
unsigned char th_flag; //6位标志位
USHORT th_win; //16位窗口大小
USHORT th_sum; //16位校验和
USHORT th_urp; //16位紧急数据偏移量
}TCPHEADER;

//CheckSum:计算校验和的子函数
USHORT checksum(USHORT *buffer, int size)
{
unsigned long cksum=0;
while(size >1)
{
cksum+=*buffer++;
size -=sizeof(USHORT);
}
if(size )
{
cksum += *(UCHAR*)buffer;
}

cksum = (cksum >> 16) + (cksum & 0xffff);
cksum += (cksum >>16);
return (USHORT)(~cksum);
}

void useage()
{
printf("******************************************\n");
printf("TCPPing\n");
printf("\t Written by Refdom\n");
printf("\t Email: refdom@263.net\n");
printf("Useage: TCPPing.exe Target_ip Target_port \n");
printf("*******************************************\n");
}

int main(int argc, char* argv[])
{
WSADATA WSAData;
SOCKET sock;
SOCKADDR_IN addr_in;
IPHEADER ipHeader;
TCPHEADER tcpHeader;
PSDHEADER psdHeader;

char szSendBuf[60]={0};
BOOL flag;
int rect,nTimeOver;

useage();

if (argc!= 3)
{ return false; }

if (WSAStartup(MAKEWORD(2,2), &WSAData)!=0)
{
printf("WSAStartup Error!\n");
return false;
}

if ((sock=WSASocket(AF_INET,SOCK_RAW,IPPROTO_RAW,NULL,0,WSA_FLAG_OVERLAPPED))==INVALID_SOCKET)
{
printf("Socket Setup Error!\n");
return false;
}
flag=true;
if (setsockopt(sock,IPPROTO_IP, IP_HDRINCL,(char *)&flag,sizeof(flag))==SOCKET_ERROR)
{
printf("setsockopt IP_HDRINCL error!\n");
return false;
}

nTimeOver=1000;
if (setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char*)&nTimeOver, sizeof(nTimeOver))==SOCKET_ERROR)
{
printf("setsockopt SO_SNDTIMEO error!\n");
return false;
}
addr_in.sin_family=AF_INET;
addr_in.sin_port=htons(atoi(argv[2]));
addr_in.sin_addr.S_un.S_addr=inet_addr(argv[1]);

//
//
//填充IP首部
ipHeader.h_verlen=(4<<4 | sizeof(ipHeader)/sizeof(unsigned long));
// ipHeader.tos=0;
ipHeader.total_len=htons(sizeof(ipHeader)+sizeof(tcpHeader));
ipHeader.ident=1;
ipHeader.frag_and_flags=0;
ipHeader.ttl=128;
ipHeader.proto=IPPROTO_TCP;
ipHeader.checksum=0;
ipHeader.sourceIP=inet_addr("本地地址");
ipHeader.destIP=inet_addr(argv[1]);

//填充TCP首部
tcpHeader.th_dport=htons(atoi(argv[2]));
tcpHeader.th_sport=htons(SOURCE_PORT); //源端口号
tcpHeader.th_seq=htonl(0x12345678);
tcpHeader.th_ack=0;
tcpHeader.th_lenres=(sizeof(tcpHeader)/4<<4|0);
tcpHeader.th_flag=2; //修改这里来实现不同的标志位探测,2是SYN,1是FIN,16是ACK探测 等等
tcpHeader.th_win=htons(512);
tcpHeader.th_urp=0;
tcpHeader.th_sum=0;

psdHeader.saddr=ipHeader.sourceIP;
psdHeader.daddr=ipHeader.destIP;
psdHeader.mbz=0;
psdHeader.ptcl=IPPROTO_TCP;
psdHeader.tcpl=htons(sizeof(tcpHeader));

//计算校验和
memcpy(szSendBuf, &psdHeader, sizeof(psdHeader));
memcpy(szSendBuf+sizeof(psdHeader), &tcpHeader, sizeof(tcpHeader));
tcpHeader.th_sum=checksum((USHORT *)szSendBuf,sizeof(psdHeader)+sizeof(tcpHeader));

memcpy(szSendBuf, &ipHeader, sizeof(ipHeader));
memcpy(szSendBuf+sizeof(ipHeader), &tcpHeader, sizeof(tcpHeader));
memset(szSendBuf+sizeof(ipHeader)+sizeof(tcpHeader), 0, 4);
ipHeader.checksum=checksum((USHORT *)szSendBuf, sizeof(ipHeader)+sizeof(tcpHeader));

memcpy(szSendBuf, &ipHeader, sizeof(ipHeader));

rect=sendto(sock, szSendBuf, sizeof(ipHeader)+sizeof(tcpHeader),
0, (struct sockaddr*)&addr_in, sizeof(addr_in));
if (rect==SOCKET_ERROR)
{
printf("send error!:%d\n",WSAGetLastError());
return false;
}
else
printf("send ok!\n");

closesocket(sock);
WSACleanup();

return 0;
}

上面这个程序不光是一个Ping的程序,也可以更改成为一个比connect()更优秀的端口扫描器。

上面这个程序实际上就是通过原始套接字发送自己构造的TCP和IP数据头,如果对这个程序作修改,也很容易改为一个SYN FLOOD的工具。SYN位前面说了,是三次握手过程的第一步,表示发出一个连接请求,这时目标主机同意的时候就会返回一个ACK SYN的数据报,来确认客户端的连接,然后需要客户端进行最后一次ACK的确认,来建立这个连接。但是,如果客户步发送一个ACK来确认,那么,服务器端就有一个缓冲来等待这个确认。当有大量的SYN缓冲等待的时候,正常的连接请求就会被放在一大堆队列中,从而影响正常用户的正常连接。同样相似的,就是RST拒绝服务了。

进行上面的探测应该是探测的第一步,比如主机活动状态,端口。接来下应该针对相应端口进行更详细的判别,以及探测主机系统。 
  • 上一篇文章:
  • 下一篇文章:
  • 最近更新
    固顶文章 爱国者安全网2007年度优秀版主评选
    普通文章 瑞星公司01月11日发布 每日计算机病毒及木马播报
    普通文章 破解博彩神助(专注彩票) V2.8.01
    推荐文章 推荐:跨站脚本执行漏洞代码的六点思路
    普通文章 Windows系统下的远程堆栈溢出 实战篇
    普通文章 Windows系统下的远程堆栈溢出 原理篇
    普通文章 MsSQLServer是如何加密口令的
    普通文章 浅谈国内的渗透评估过程
    普通文章 Dvbbs8.1 0DAY(通杀Access和mssql版本)
    普通文章 微软:我们的代码比赛门铁克更安全
    热门文章
    普通文章提醒:“求职信”病毒1月6日发作
    普通文章两条“蠕虫”蠢蠢欲动
    普通文章5“网银大盗”狂盗储户14万 武汉男子被判10年
    普通文章“木马事件”终告结束 英语学习网重获新生
    普通文章搜索引擎不再喜欢新米,并非只是CN米
    普通文章蠕虫"威金"新变种 "小熊猫"屠宰多个计算机系统
    普通文章元旦上网谨防“Real蛀虫” 通过视频文件传播
    普通文章入侵工具Knark的分析及防范
    普通文章认清本质 计算机病毒防治常遇问题
    普通文章饶过现代Anti-Rookit工具的内核模块扫描(ZT)
    精彩专题