The official repos have CakePHP 1.3.15, but this version is old and the CakePHP documentation for 1.3 is flaky (20140610 – 502 Bad Gateway).
To install the latest CakePHP source, we need to be running a later version of PHP than is available on the official repos, so let’s add a new repo to the /etc/sources.list file:
deb http://packages.dotdeb.org wheezy all deb-src http://packages.dotdeb.org wheezy all
Once you’ve added these repos to the file, you need to update the list of available packages:
Now you’re ready to install the packages you need from the dotdeb repo:
aptitude install php5 mysql-server php5-intl php5-mcrypt php5-mysql
In order to install composer (which you’ll need to grab CakePHP), you need to install curl and git:
aptitude install curl git
Now that’s done you can install composer:
root@debian:~# curl -s https://getcomposer.org/installer | php #!/usr/bin/env php All settings correct for using Composer Downloading... Composer successfully installed to: /root/composer.phar Use it: php composer.phar root@debian:~#
The last step is to install the CakePHP package and dependencies:
root@debian:~# mkdir php root@debian:~# mv composer.phar php/ root@debian:~# cd /var/www/ root@debian:/var/www# ls -alh total 12K drwxr-xr-x 2 root root 4.0K Jul 8 11:58 . drwxr-xr-x 12 root root 4.0K Jul 8 11:58 .. -rw-r--r-- 1 root root 177 Jul 8 11:58 index.html root@debian:/var/www# php /root/php/composer.phar create-project -s dev cakephp/app Installing cakephp/app (dev-master 05bdc480602ea7c736815f51c059f844fc26c4b5) - Installing cakephp/app (dev-master master) Cloning master Created project in /var/www/app Loading composer repositories with package information Installing dependencies (including require-dev) - Installing ircmaxell/password-compat (1.0.3) Downloading: 100% - Installing nesbot/carbon (1.8.0) Downloading: 100% - Installing cakephp/cakephp (3.0.x-dev 160f56c) Cloning 160f56c557baa5514f3781ecbf2389510f3dc9e4
I created a php directory under /root and moved the composer.phar file to tidy things up a bit. Before running the command to install CakePHP make sure you change to the directory you want to install the app into.
Make sure you set the DocumentRoot to /var/www/app (or whatever your path) and AllowOverride All so the htaccess files can be applied. You also need to enable mod_rewrite in Apache:
a2enmod rewrite apachectl restart
I’ve just created a keygen for the “monkey keygen #1” challenge on crackmes.de, it was fun and far from “boring crap” which it has been rated as on the site. If this challenge is considered by some to be easy to keygen then consider me humbled, this was a difficult and rewarding challenge for me. This post is going to be long and technical, if you don’t know the difference between eax and al then I suggest you stop reading here :)
Being fairly new to the RE game I decided to search for a string which indicated a valid key had been entered into the program. I managed to find this string at 0x46666C, contents being ‘Valid Key’. That’s cool, let’s see all references to this string:
UMessageBoxValidKey is a custom name I assigned to the subroutine when I had established this was responsible for displaying the message box. Okay, let’s see what’s going on in the UMessageBoxValidKey subroutine:
CODE:00466580 ; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ CODE:00466580 CODE:00466580 ; Attributes: bp-based frame CODE:00466580 CODE:00466580 UMessageBoxValidKey proc near ; DATA XREF: CODE:00466521o CODE:00466580 CODE:00466580 var_18 = dword ptr -18h CODE:00466580 var_14 = dword ptr -14h CODE:00466580 var_10 = dword ptr -10h CODE:00466580 var_C = dword ptr -0Ch CODE:00466580 var_8 = dword ptr -8 CODE:00466580 var_4 = dword ptr -4 CODE:00466580 CODE:00466580 push ebp CODE:00466581 mov ebp, esp CODE:00466583 add esp, 0FFFFFFE8h CODE:00466586 xor ecx, ecx CODE:00466588 mov [ebp+var_18], ecx CODE:0046658B mov [ebp+var_14], ecx CODE:0046658E mov [ebp+var_C], ecx CODE:00466591 mov [ebp+var_10], edx CODE:00466594 mov [ebp+var_4], eax CODE:00466597 xor eax, eax CODE:00466599 push ebp CODE:0046659A push offset loc_466660 CODE:004665BD xor eax, eax CODE:004665BF push ebp CODE:004665C0 push offset sub_466636 CODE:004665C5 push dword ptr fs:[eax] CODE:004665C8 mov fs:[eax], esp CODE:004665CB lea eax, [ebp+var_C] CODE:004665CE push eax CODE:004665CF lea edx, [ebp+var_14] CODE:004665D2 mov eax, [ebp+var_4] CODE:004665D5 mov eax, [eax+2FCh] CODE:004665DB call sub_4320E8 CODE:004665E0 mov edx, [ebp+var_14] CODE:004665E3 mov cx, 4DE1h CODE:004665E7 mov eax, [ebp+var_8] CODE:004665EA call sub_466230 CODE:004665EF lea edx, [ebp+var_18] CODE:004665F2 mov eax, [ebp+var_4] CODE:004665F5 mov eax, [eax+300h] CODE:004665FB call sub_4320E8 CODE:00466600 mov eax, [ebp+var_18] CODE:00466603 mov edx, [ebp+var_C] CODE:00466606 call UCheckValidCombo CODE:0046660B jnz short loc_466620 CODE:0046660D push 0 ; uType CODE:0046660F push offset aValidKey ; "Valid Key" CODE:00466614 push offset aValidKey ; "Valid Key" CODE:00466619 push 0 ; hWnd CODE:0046661B call MessageBoxA_0 CODE:00466620 CODE:00466620 loc_466620: ; CODE XREF: UMessageBoxValidKey+8Bj CODE:00466620 xor eax, eax CODE:00466622 pop edx CODE:00466623 pop ecx CODE:00466624 pop ecx CODE:00466625 mov fs:[eax], edx CODE:00466628 push offset loc_46663D CODE:0046662D CODE:0046662D loc_46662D: ; CODE XREF: CODE:0046663Bj CODE:0046662D mov eax, [ebp+var_8] CODE:00466630 call sub_4030FC CODE:00466635 retn CODE:00466635 UMessageBoxValidKey endp ; sp = -30h
Okay so if this challenge allowed for patching, all that would be necessary to fool the program into thinking you had entered a correct key would be to NOP out the jnz op at 0x0046660B. Unfortunately for us the task is to create a keygen, so we need to find the code responsible for generating and checking the key. UCheckValidCombo looks like a good place to start.
CODE:004043AC ; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ CODE:004043AC CODE:004043AC CODE:004043AC UCheckValidCombo proc near ; CODE XREF: sub_414450+6Bp CODE:004043AC ; sub_418FBC+Ep ... CODE:004043AC push ebx CODE:004043AD push esi CODE:004043AE push edi CODE:004043AF mov esi, eax CODE:004043B1 mov edi, edx CODE:004043B3 cmp eax, edx CODE:004043B5 jz loc_40444A CODE:004043BB test esi, esi CODE:004043BD jz short loc_404427 CODE:004043BF test edi, edi CODE:004043C1 jz short loc_40442E CODE:004043C3 mov eax, [esi-4] CODE:004043C6 mov edx, [edi-4] CODE:004043C9 sub eax, edx CODE:004043CB ja short loc_4043CF CODE:004043CD add edx, eax CODE:004043CF CODE:004043CF loc_4043CF: ; CODE XREF: UCheckValidCombo+1Fj CODE:004043CF push edx CODE:004043D0 shr edx, 2 CODE:004043D3 jz short loc_4043FB CODE:004043D5 CODE:004043D5 loc_4043D5: ; CODE XREF: UCheckValidCombo+45j CODE:004043D5 mov ecx, [esi] CODE:004043D7 mov ebx, [edi] CODE:004043D9 cmp ecx, ebx CODE:004043DB jnz short loc_404435 CODE:004043DD dec edx CODE:004043DE jz short loc_4043F5 CODE:004043E0 mov ecx, [esi+4] CODE:004043E3 mov ebx, [edi+4] CODE:004043E6 cmp ecx, ebx CODE:004043E8 jnz short loc_404435 CODE:004043EA add esi, 8 CODE:004043ED add edi, 8 CODE:004043F0 dec edx CODE:004043F1 jnz short loc_4043D5 CODE:004043F3 jmp short loc_4043FB CODE:004043F5 ; --------------------------------------------------------------------------- CODE:004043F5 CODE:004043F5 loc_4043F5: ; CODE XREF: UCheckValidCombo+32j CODE:004043F5 add esi, 4 CODE:004043F8 add edi, 4 CODE:004043FB CODE:004043FB loc_4043FB: ; CODE XREF: UCheckValidCombo+27j CODE:004043FB ; UCheckValidCombo+47j CODE:004043FB pop edx CODE:004043FC and edx, 3 CODE:004043FF jz short loc_404423 CODE:00404401 mov ecx, [esi] CODE:00404403 mov ebx, [edi] CODE:00404405 cmp cl, bl CODE:00404407 jnz short loc_40444A CODE:00404409 dec edx CODE:0040440A jz short loc_404423 CODE:0040440C cmp ch, bh CODE:0040440E jnz short loc_40444A CODE:00404410 dec edx CODE:00404411 jz short loc_404423 CODE:00404413 and ebx, 0FF0000h CODE:00404419 and ecx, 0FF0000h CODE:0040441F cmp ecx, ebx CODE:00404421 jnz short loc_40444A CODE:00404423 CODE:00404423 loc_404423: ; CODE XREF: UCheckValidCombo+53j CODE:00404423 ; UCheckValidCombo+5Ej ... CODE:00404423 add eax, eax CODE:00404425 jmp short loc_40444A CODE:00404427 ; --------------------------------------------------------------------------- CODE:00404427 CODE:00404427 loc_404427: ; CODE XREF: UCheckValidCombo+11j CODE:00404427 mov edx, [edi-4] CODE:0040442A sub eax, edx CODE:0040442C jmp short loc_40444A CODE:0040442E ; --------------------------------------------------------------------------- CODE:0040442E CODE:0040442E loc_40442E: ; CODE XREF: UCheckValidCombo+15j CODE:0040442E mov eax, [esi-4] CODE:00404431 sub eax, edx CODE:00404433 jmp short loc_40444A CODE:00404435 ; --------------------------------------------------------------------------- CODE:00404435 CODE:00404435 loc_404435: ; CODE XREF: UCheckValidCombo+2Fj CODE:00404435 ; UCheckValidCombo+3Cj CODE:00404435 pop edx CODE:00404436 cmp cl, bl CODE:00404438 jnz short loc_40444A CODE:0040443A cmp ch, bh CODE:0040443C jnz short loc_40444A CODE:0040443E shr ecx, 10h CODE:00404441 shr ebx, 10h CODE:00404444 cmp cl, bl CODE:00404446 jnz short loc_40444A CODE:00404448 cmp ch, bh CODE:0040444A CODE:0040444A loc_40444A: ; CODE XREF: UCheckValidCombo+9j CODE:0040444A ; UCheckValidCombo+5Bj ... CODE:0040444A pop edi CODE:0040444B pop esi CODE:0040444C pop ebx CODE:0040444D retn CODE:0040444D UCheckValidCombo endp
So, the cmp at 0x004043B3 is interesting because the EDX register appears to contain a string which could be the key. Let’s test this..
Let’s enter the “2C6B91” string as the key with the name “aaa”.
Yay, that’s not terribly good practice, storing the answer in a string like that. It would be more convoluted in ‘real life’ one would hope. Okay, let’s insert a write break so we know which subroutine is responsible for populating this part of memory. So far we can either patch or generate keys using the challenge binary to bypass it, but we really need to create our own binary to prove that we understand how the key is created (something we don’t yet know).
CODE:004028B8 ; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ CODE:004028B8 CODE:004028B8 CODE:004028B8 sub_4028B8 proc near ; CODE XREF: sub_4025F8+81p CODE:004028B8 ; sub_402A08+14p ... CODE:004028B8 push esi CODE:004028B9 push edi CODE:004028BA mov esi, eax CODE:004028BC mov edi, edx CODE:004028BE mov eax, ecx CODE:004028C0 cmp edi, esi CODE:004028C2 ja short loc_4028D7 CODE:004028C4 jz short loc_4028F5 CODE:004028C6 sar ecx, 2 CODE:004028C9 js short loc_4028F5 CODE:004028CB rep movsd CODE:004028CD mov ecx, eax CODE:004028CF and ecx, 3 CODE:004028D2 rep movsb CODE:004028D4 pop edi CODE:004028D5 pop esi CODE:004028D6 retn CODE:004028D7 ; --------------------------------------------------------------------------- CODE:004028D7 CODE:004028D7 loc_4028D7: ; CODE XREF: sub_4028B8+Aj CODE:004028D7 lea esi, [ecx+esi-4] CODE:004028DB lea edi, [ecx+edi-4] CODE:004028DF sar ecx, 2 CODE:004028E2 js short loc_4028F5 CODE:004028E4 std CODE:004028E5 rep movsd CODE:004028E7 mov ecx, eax CODE:004028E9 and ecx, 3 CODE:004028EC add esi, 3 CODE:004028EF add edi, 3 CODE:004028F2 rep movsb CODE:004028F4 cld CODE:004028F5 CODE:004028F5 loc_4028F5: ; CODE XREF: sub_4028B8+Cj CODE:004028F5 ; sub_4028B8+11j ... CODE:004028F5 pop edi CODE:004028F6 pop esi CODE:004028F7 retn CODE:004028F7 sub_4028B8 endp
The rep movsb instruction at 0x004028F2 copies strings from [ESI] to [EDI], so we need to insert another write break at the ESI address specified (0x0012F5B9).
I needed to repeat this process a couple of times to find the subroutine which was responsible for checking the key, but eventually I determined it was sub_466230. If you look in the screenshot it’s a couple of subroutines up from the routine responsible for the 0x0012F5B9 write. Here’s sub_466230, the heart of the program.
CODE:00466230 ; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ CODE:00466230 CODE:00466230 ; Attributes: bp-based frame CODE:00466230 CODE:00466230 sub_466230 proc near ; CODE XREF: UMessageBoxValidKey+6Ap CODE:00466230 CODE:00466230 var_1C = dword ptr -1Ch CODE:00466230 var_18 = dword ptr -18h CODE:00466230 var_12 = word ptr -12h CODE:00466230 var_10 = dword ptr -10h CODE:00466230 var_B = byte ptr -0Bh CODE:00466230 var_A = word ptr -0Ah CODE:00466230 var_8 = dword ptr -8 CODE:00466230 var_4 = dword ptr -4 CODE:00466230 arg_0 = dword ptr 8 CODE:00466230 CODE:00466230 push ebp CODE:00466231 mov ebp, esp CODE:00466233 add esp, 0FFFFFFE4h CODE:00466236 push ebx CODE:00466237 xor ebx, ebx CODE:00466239 mov [ebp+var_1C], ebx CODE:0046623C mov [ebp+var_A], cx CODE:00466240 mov [ebp+var_8], edx CODE:00466243 mov [ebp+var_4], eax CODE:00466246 xor eax, eax CODE:00466248 push ebp CODE:00466249 push offset sub_4662E9 CODE:0046624E push dword ptr fs:[eax] CODE:00466251 mov fs:[eax], esp CODE:00466254 mov ax, [ebp+var_A] CODE:00466258 mov [ebp+var_12], ax CODE:0046625C mov eax, [ebp+arg_0] CODE:0046625F call sub_403FA0 CODE:00466264 mov eax, [ebp+var_8] CODE:00466267 call sub_404260 CODE:0046626C test eax, eax CODE:0046626E jle short loc_4662D3 CODE:00466270 mov [ebp+var_18], eax CODE:00466273 mov [ebp+var_10], 1 CODE:0046627A CODE:0046627A loc_46627A: ; CODE XREF: sub_466230+A1j CODE:0046627A mov eax, [ebp+var_8] CODE:0046627D mov edx, [ebp+var_10] CODE:00466280 mov al, [eax+edx-1] CODE:00466284 movzx edx, [ebp+var_12] CODE:00466288 shr edx, 8 CODE:0046628B xor al, dl CODE:0046628D mov [ebp+var_B], al CODE:00466290 xor eax, eax CODE:00466292 mov al, [ebp+var_B] CODE:00466295 add ax, [ebp+var_12] CODE:00466299 mov edx, [ebp+var_4] CODE:0046629C imul word ptr [edx+4] CODE:004662A0 mov edx, [ebp+var_4] CODE:004662A3 add ax, [edx+6] CODE:004662A7 mov [ebp+var_12], ax CODE:004662AB lea ecx, [ebp+var_1C] CODE:004662AE xor eax, eax CODE:004662B0 mov al, [ebp+var_B] CODE:004662B3 mov edx, 2 CODE:004662B8 call USubKeyCalcNO CODE:004662BD mov edx, [ebp+var_1C] CODE:004662C0 mov eax, [ebp+arg_0] CODE:004662C3 call sub_404268 CODE:004662C8 mov eax, [ebp+arg_0] CODE:004662CB inc [ebp+var_10] CODE:004662CE dec [ebp+var_18] CODE:004662D1 jnz short loc_46627A CODE:004662D3 CODE:004662D3 loc_4662D3: ; CODE XREF: sub_466230+3Ej CODE:004662D3 xor eax, eax CODE:004662D5 pop edx CODE:004662D6 pop ecx CODE:004662D7 pop ecx CODE:004662D8 mov fs:[eax], edx CODE:004662DB push offset loc_4662F0 CODE:004662E0 CODE:004662E0 loc_4662E0: ; CODE XREF: CODE:004662EEj CODE:004662E0 lea eax, [ebp+var_1C] CODE:004662E3 call sub_403FA0 CODE:004662E8 retn CODE:004662E8 sub_466230 endp ; sp = -28h
Okay, this key algorithm is quite involved:
1. al = <nth character in name> 2. edx = 0x4DE1 (or eax if 2nd or more character pass) 3. dl = dl >> 8 (0x4D in this case) 4. al = al ^ 0x4D (0x2C in this case) 5. ax = ax + 0x4DE1 (or eax as it was at step 2 if 2nd or more character pass) (0x4ED0 in this case) 6. ax = ax * 0xCE6D = (0xB189) 6. ax = ax + 0x58BF (0x0A48 (which will be edx in the next round))
Should be accurate (might not be). If that dosen’t make sense, just have a look at the C code (which does work, for me at least).
At first, this code didn’t work at all because the bit shifting I was doing was only 2 bits (as indicated by the commented out debug printf). Once I had fixed that it was necessary to uppercase the hex output and ensure that in case the value was less than 16, a 0 is prepended to the string.
You may remember my post slagging off BT about their piss poor performance regarding Internet speeds and slow remediation techniques. In the end, the problem was down to some old copper wire stretching from the telephone pole to the master socket in the property. It was patched up (twice) and everything was fine for about 5 minutes. Over the course of the last couple months the net began slowing down from 400-500KB/sec, to 250KB/sec, to 140KB/sec.
I started looking into alternatives such as satellite, and then came crashing back down to earth when I researched the upfront cost for the gear, the limited data allowance (even on ‘unlimited’ plans), the latency between you and the rest of the world, and the relatively lame connection speed. Determined to get my Internet back to the glory days of 450KB/sec, I ventured outside to check the integrity of the cable from the telephone pole to the master socket. I came across this:
This part of the cable had obivously been subject to some trauma, the jacket had split and it had been squashed. I decided that squeezing it might make my Internet faster, so I did. I laughed it off and rebooted my router to see what would happen. Upopn conducting a speed test, I noticed my Internet speed was now three times faster than 5 minutes ago. I laughed again, and got some PVC tape on that shit. Now I just need to get around to calling BT to fix it properly.. maybe later.
Ball ache level, AI without memory is hard, so I cheated a bit.
Cool site with JS-based challenges. Here are my solutions thus far:
I’m not sure the authors intended for some of the methods I used, but that’s half the fun..
I have been asked to revoke access to some of my blog posts relating to some technical challenges which were being used inappropriately, diminishing their educational potential for some individuals. [Retracted, nothing to see here] I’ll leave you with a summary of the challenges I had provided technical details for, without revealing the answers. [Retracted] The following posts have been made inaccessible on this website, any references to these posts made on any other site are not under my control and cannot be retracted by me:
- Bacterial Vaginosis – Windows Domain Pwning
- AIDS – Windows 2000 challenge
- HIV – File upload
- Genital Warts – X11
- Syphilis – Third party software challenge
- Crabs – SNMP challenge
- Chlamydia – PostgreSQL challenge
- Gonorrhea – chroot challenge #2
- Hepatitis – chroot challenge
- Scabies – Network challenge
- Hackme challenge #2 – Weak encryption
The majority of the challenges, and indeed real life engagements, can be broken down into roughly three distinct phases (excluding scoping); recon, attack, and report. The recon phase is important, if not the most important phase, because any mishaps here could lead to pain down the line when you don’t find any vector in the stuff you’ve discovered. The recon phase involves establishing what is accessible, usually through port scans. You have a selection of tools you can use here, including:
My approach typically involves firing masscan to get some quick hits and then running nmap while looking at the results of the masscan. masscan is quick, which is why I use it first, but it can also be inaccurate insofar as nmap reporting open ports masscan didn’t. That’s fine for a quick pass, as long as it is backed up by an nmap scan.
Once I’ve established TCP connectivity, I’ll move onto udp-proto-scanner, which covers some of the UDP ports. For full coverage, I’d use nmap -sU, but for the standard services udp-proto-scanner is sufficient (maybe even better), because it sends the expected datagram for the service on that port.
Recon doesn’t end at port discovery though – depending on the service listening, I’d consider version reconnaissance, directory bruting, user enumeration, and unauthenticated web spidering, just be wary you don’t breach the scope.
The line between recon and attack is murky. If an attacker pulls the MySQL version via unsanitised user input is that recon or attack, or both? The recon and attack phases cannot be represented as two distinct junks on a timeline, they compliment and feed into one another, and happen constantly over the course of an engagement.
The reporting phase is designated for creating a document which encapsulates the work you’ve done for the client in a form which is digestable by non-technical people, while also providing technical details of any findings which merit mention.
The report should include an ‘executive’ summary, which provides a 10 000 foot view of the issues raised in the target test, as well as more technical details, to prove and demonstrate vulnerable vectors.
Okay, enough fluffy bullshit, let’s get technical. One of the problems with the challenges I wrote about is rooted in the fact that discrepancies between them stick out. That is, if one challenge box has a port open that isn’t open on any other challenge boxes, you can be relatively sure that this will be your vector. In real life, this won’t necessarily be the case. Another issue with challenges in general is that as an attacker, you know that the target is vulnerable *somehow*, this acts as a sort of motivator, which you wouldn’t inhibit on a real engagement, because some targets won’t necessarily be vulnerable, no matter how hard you try.
That isn’t to say the challenges aren’t useful – on the contrary, I believe them to be instrumental in standardising my recon process, as well as refining my knowledge in rooting Linux boxes, which is why I consider it a shame that I cannot share the technical details with you, the reader … [retracted, I shouldn’t keep this bit]. I would like to [retracted] apologise on behalf of my employer for this. Sorry.
Once you’ve got a standard user account on a Linux box, typically through a network service, the things you should be looking out for are:
- File permissions
- SSH keys
- Local ports
- Binaries which interact with files on the filesystem with suspect permissions
- Third party tools
- Log files
- Sudo capabilites (sudo -l)
- Shell histories (.bash_history / .zsh_history)
It may sound like an oxymoron, but it’s a legitimate concern among the good guys in the security industry. Under the circumstance that a company has authorised you to try and hack into their live system, you really don’t want to be pissing around with ‘dangerous’ SQL injections. Dangerous is defined here as an SQL injection which results in undesirable data modification in the database, which could have otherwise have been avoided if the SQLi was considered more carefully (or wasn’t present in the first place). Let’s have a quick demonstration.
Mr Developer decides that passing unsanitised user input is a good idea, and that prepared statements are not. He wants to use a SELECT query to determine if the username and password are correct, and he also wants to update a table containing login information using an UPDATE statement. The company Mr Developer works for have received a tip that the developer might be a bit of a tit, and decide to hire Mr Security Man to try and break into Mr Developer’s web application. Unfortunately, Mr Security Man is also a bit of a tit, and thinks that still using some variant of ‘ or 1=1 — is a good idea. Let’s see how it all unravels:
SELECT * FROM tbl_test WHERE username = 'test' AND password = 'pass';
Above we have an innocent enough looking SQL statement. The attacker finds the login form associated with this statement and injects the password field with ‘ or 1=1 —
SELECT * FROM tbl_test WHERE username = 'test' AND password = 'pass' or 1=1 -- '
Mr Security Man is excited, he’s bypassed the login form and is now sitting on the site with a message reaffirming his suspicion that his non-skiddy SQLi has landed him the test user. “Hello test!”. Excellent.
Unfortunately, Mr Security Man didn’t realise that Mr Developer runs an UPDATE statement on an audit table using his username and password. This is where brown hits blade.
mysql> select * from audit; +------+----------+----------+------------+ | id | username | password | last_login | +------+----------+----------+------------+ | 1 | test | pass | yesterday | | 2 | admin | password | yesterday | +------+----------+----------+------------+ 2 rows in set (0.00 sec) mysql> mysql> UPDATE audit SET last_login = 'today' WHERE username = 'test' AND password ='pass' or 1=1 -- ' -> ; Query OK, 2 rows affected (0.01 sec) Rows matched: 2 Changed: 2 Warnings: 0 mysql> select * from audit; +------+----------+----------+------------+ | id | username | password | last_login | +------+----------+----------+------------+ | 1 | test | pass | today | | 2 | admin | password | today | +------+----------+----------+------------+ 2 rows in set (0.00 sec) mysql>
Whoops? It’s okay though right because it’s only an audit table? Well, not really. It was only an audit table in this example, and a few things had to happen for this injection to be ‘dangerous’, but are they that inconceivable in real life?
Okay, so if ‘ or 1=1 — is bad, what should be used instead? Well, that’s a tough question, because any form of SQLi transforms the structure of the statement, which could potentially manipulate data in ways unintended or by second-order. I’m currently of the opinion that the safest way to test for SQLi is by forcing a syntax error. Doing this shouldn’t get you passed a login page, but it will at least indicate the presence of an SQL injection.
A slightly riskier stratedgy would be the utilisation of the ORDER BY or LIMIT clauses, or the BENCHMARK function. While the web app probably has to be of particularly bad quality for the aforementioned clauses or function to result in undesirable data modification, this is still a possibility you have to assume if you don’t want to be Mr Security Man.