The goal of this challenge is to read the flag from AWS Secret Manager. The ARN is known (arn:aws:secretsmanager:eu-central-1:562778112707:secret:secret-flag-Educated-Assumption
) and we got leaked AWS credential (access key ID, secret access key, and session token). We could configure the local aws
cli to use the credential.
First, we want to know the associated identity of the credential.
The identity is AWS IAM role with name role_for-lambda-to-assume-role
in the account 743296330440
. We need to find a way to use this role to read the target secret ARN in the target account (562778112707
).
It happened that this role has permission to call iam get-role
to retrieve the role's information.
There is a permission boundary defined with the policy with ARN arn:aws:iam::743296330440:policy/permission-boundary_restrict-assumptions
. Fortunately, the role has permission to call iam get-policy
and iam get-policy-version
to gather further information about the policy.
Use the default version ID of the policy (v9
).
The policy allows current role to call sts assume-role
to another role (arn:aws:iam::*:role/role_to_secretsmanager_read_flag
) as long as the sts
API call provides the valid external ID as parameter. From the challenge's description, we know that our target account is 562778112707
so we can try to assume role as arn:aws:iam::562778112707:role/role_to_secretsmanager_read_flag
.
We got temporary credential for the desired role. After reconfigure the local aws
cli to use the credential, we can try to do enumeration further to know the permissions of this role but we can try to get the value of target secret storage directly from the desired AWS Secret Manager ARN. From the target ARN, we also know that the region is eu-central-1
.
flag: ENO{uR-boundry_m@de-me#Assume}
We are given the following script.
The service encrypts the flag + our input + a random padding, we can minimize the padding by sending the longest input allowed, so the random padding will be around 128 bits, since the e = 3, we can do a coppersmith short pad attack to recover the flag.
The script originated from here.
flag: ENO{we11_5eem5_lik3_128_r4ndom_b1ts_4r3_n0t_3n0ugh}
We are given a following script.
The service encrypts the same message with only difference is in the middle where the round number changes. It is then possible to know the difference between each message, hence we can perform franklin-reiter related message attack, one problem is the token length is unknown so we cannot count the difference between the message (Think of it like this, the difference between AAAAA -> BAAAA
is not the same as AAAAAAAAAAA -> BAAAAAAAAAA
). But assuming the length of the flag is somewhat reasonable and because the token have the same length as the flag, we can simply bruteforce the length of the token.
flag: ENO{th3_s0lut1on_i5_n0t_th4t_1337}
We're given the 3 python scripts. Here's the one of the script called curvy_decryptor.py
where the main flow of this challenge is located.
This script implements the Elgamal encryption based on Elliptic Curve. It uses private key d_a
to decrypt any encrypted message and public key P_a
where P_a = G * d_a
to encrypt any message.
TL;DR
m
into B
and c
where B = G * d_b
and c = m + (P_a * d_b)
B
and c
from user, then recover m
by computing c - (B * d_a)
c - (B * d_a) = m + (P_a * d_b) - (G * d_b * d_a) = m + (G * d_a * d_b) - (G * d_b * d_a) = m
Since we have a full control over B
and c
, we can trick the decryption process by trying to decrypt the message m + G
so that the string "ENO" doesn't appear in the decryption result. As we have the decrypted result (which is the x-coordinate of point m + G
), then we can calculate the original m
locally by subtracting it with G
.
Let's take the P_a
, B
, and c
values to our solver script.
flag: ENO{ElGam4l_1s_mult1pl1cativ3}
We are given the following script and the generated output.
We're not given any factor of modulus N, but fortunately we have 4 numbers a, b, c, d which satisfy a^2 + b^2 = c^2 + d^2 = n. Since modulus N is obviously not a prime number and can be expressed as the sum of two squares in two distinct ways, it can be written as a product of two integers each of which is a sum of two squares.
flag: ENO{Gauss_t0ld_u5_th3r3_1s_mor3_th4n_on3_d1men5i0n}
We are given the following script:
Looking at the script, we can see that the flag is at the first element of a
, that is a[0] = flag
let's take a look at how the shares are generated
Here we can see that the very first element of s
uses x = 0
, which means that all x**i
should be all 0 and thus px = 0
, HOWEVER, in python, 0**0
is actually a 1, which means that px = a[0] * 1 = a[0] = flag
so by getting the very first share, we immediately got the flag.
We can't access index 0 directly, but since we can choose sid up to sss.n
, then sss.n % sss.n = 0
flag: ENO{SeCr3t_Sh4m1r_H4sh1ng}
We were given a binary. The information about the binary can be seen below:
Decompiled binary:
The program ask the user for input a data using the gets() function which doesn't perform a boundary check, so it will cause a vulnerability called Buffer Overflow. Since there's a function to read and print the content of the flag file (heavens_secret
function), we can perform ROP to do ret2win (return to the heavens_secret
function).
Solver:
flag: ENO{h34v3nly_4ddr355_f0r_th3_w1n}
We were given a binary file and it source code. Here's the binary information and the source code of the binary.
Binary Information:
Source code:
The program will leak the stack address by printing it using the printf() with "%p" format (it will print the address of the username
variable). Then, the program will ask the user to input data using the read()
function with 1024 bytes as it maximal input size, and it will store the data into the username
variable. However, since the variable 'username' can only hold data up to 512 bytes, this results in a buffer overflow vulnerability.
Due to the NX protection being disabled (which means the stack has permission rwx), we can inject a shellcode into the payload to gain a shell. To obtain the shellcode, simply overwrite the saved return instruction pointer (RIP) with the address of the 'username' variable using a Buffer Overflow.
Solver:
flag: ENO{Even_B4B1es_C4n_H4ck!}
We were given a binary and three libraries file. The binary and the library files information can be seen below.
Binary Information:
Library Information:
Let's take a look at the decompiled binary code below
The program will ask the user to input a username and password. Then it will hash the password using the SHA1 Hash Algorithm. The SHA1()
function requires three parameters: arg1
is a pointer where the string to be hashed is stored, arg2
is the size/length of the string in arg1
, and arg3
is a pointer where the hash result will be stored. The SHA1()
function hashes the password entered by the user, producing a 20-byte hash, which is stored in the hashed_password
variable within the login__sub_1329
function. Notably, the hashed_password
variable can only hold data up to 18 bytes, while the data stored is 20 bytes, creating a 2-byte buffer overflow vulnerability that can be exploited to overwrite the value of the status
variable.
What we need to do is find a string that, when it hashed with SHA1, results in two trailing null bytes. The purpose is to allow these two null bytes to overwrite the value of the status variable, which originally holds the value 0x1337, and change it to 0.
helper.py:
Solver:
flag: ENO{C_H4SHing_1s_H4rd:D}
ELF file 64bit, there's a Bufferoverflow bug on main() function
NO PIE & No Canary, but there's no gadget that we can use to leak libc, like pop_rdi or csu_gadget, to solve this, I overwrite LSB of libc_start_main_ret to libc_start_main_ret-7, with this we back to main and got the libc leak.
Solver:
flag: ENO{You're_g00d_and_gett1ng_b3ttr!}
Flag in rules
flag: ENO{th1s_is_4n_eXample}
An ELF binary compiled using nim language
We can see the main code at NimMainModule()
Important code:
wheel__bicycle_2()
function07740277000105007572727106040400
wheel__bicycle_2()
ENO{
and ends with }
ENO{
and }
, convert to lowercase, then check if all characters are only in hex characters (0123456789abcdef)ENO{
and }
into two parts. Encode each parts using a specific algorithmThe following is the python implementation of the encoding process
To solve this, we are using z3. After we found the flag that passed the checker, submit it to the remote server to get the correct flag.
flag: ENO{C0F3DEADBEEF1337}
ELF crackme with 5 checks, it will immediately segfault if any check fails.
ENO{
.flag[i]
xored with flag[i+14]
and the sum of all 8 characters after xor should be 0x1F4
.flag[i]
xored with flag[i+14]
and the multiplication of all characters after xor should be 0x3A49D503C4C0
.0x13
and the result should be R]WL^aA|q#g
}
.0x67123A46
.flag: ENO{H4CK3RS_AND_MrRob0t}
All these checks:
can be bypassed by using IP address with the last part starts with 0: 192.168.112.02
. The file_get_contents
function will normalize the IP into 192.168.112.2
and fetch the content.
flag: ENO{Another_Fl4G_something_IP_STuff!}
Given this code:
Variable $password
is hashed into raw output. We just need to find the input that gives SQL injection. We modified hasherbasher from here https://github.com/gen0cide/hasherbasher to accept md5(md5(input)) instead. We found 6pNKKedhmuEETxbpHVK
as the input, containing SQL injection payload xgCߩ#i��b_'oR'6
as the output.
flag: ENO{It's_always_MD5-N3ever_Trust_1t!}
Given this code:
We can upload .php
file using:
.gif
as the extension of file.php
and .gif
Then open http://52.59.124.14:10021/images/weweweww.php?c=cat%20../flag*
to get the flag.
flag: ENO{4n_uplo4ded_f1l3_c4n_m4k3_wond3r5}
As the encryption mode is ECB, every plaintext block will be encrypted into a same block. We can forge our input so it contains admin=1
.
ffff&
.ffff&_id=00000000&admin=1&color=ffff&
da5ef5449dcf37a33cecc578f8c7a6c68ec11e84f19bd24ddaac2f43b5efd47edb8af08fe75975e04aebefc123bf920e71090921e9d924daf0edf294e24da982e33815146a57b246e08907f12b6b97e4
session=db8af08fe75975e04aebefc123bf920e71090921e9d924daf0edf294e24da982;
flag: ENO{W3B_H4S_Crypt0!}
As the code is using extract
function, it can overwrite any variable. Create this HTTP request to get the flag.
flag: ENO{N3ver_3xtract_ok?}
We have database.db, containing hashed SHA-1 password of admin: 0e[numbers]
. With type juggling in PHP, we just need to find input that has SHA-1 of 0e[any_numbers]
, e.g. aaroZmOk
. Login with admin:aaroZmOk
and get the flag.
flag: ENO{m4ny_th1ng5_c4n_g0_wr0ng_1f_y0u_d0nt_ch3ck_typ35}
Description
There was weird traffic on port 10000. Apparently employee 'astroza' tried to bypass our firewall restrictions using a udptunnel tool obtained from GitHub. They said we won't be able to see the traffic, since the tool configures a 'password' to run.
Given a network capture packet named udopee.pcap
, we can use tshark
to observe the packet's hierarchy.
Here, we have found that the majority of packets are UDP, and all of them have a data field. Furthermore, the data itself contains a byte-pattern similar to the IPv4 packet header (\x45\x00
), which led us to believe that it is indeed tunneled traffic.
Returning to the description, it was stated that the traffic is tunneled using the udptunnel
tool. Normally, the original IPv4 bytes would be inserted inside udp.data. However, in this case, there are 2 reserved bytes preceding the actual IPv4 bytes
There are several ways to exfiltrate the original traffic, including using tools like editcap
or scapy
. The editcap approach can be accomplished by removing unnecessary bytes, starting from the IPv4 + UDP header up to the 2 reserved data bytes.
Here, we can observe that the original traffic, sourced from 10.0.0.2 to 10.0.0.1, most likely carried a certain TCP data. By employing tshark
once again, we can extract the data field and further process it.
flag: ENO{AN0TH3R_TUNN3L_AN0THER_CHALL}
The challenge is a Rust jail written in a simple bash script.
We can communicate with the bash script remotely via nc 52.59.124.14 10075
.
From the bash script, we know that:
src/lib.rs
.!
are stripped, presumably to avoid any call to macro.#![no_std]
, which is a crate-level attribute that indicates that the crate will link to the core-crate instead of the std-crate.#![no_std]
, the code can't use std
directly such as println
, process
, or fs
.src/main.rs
will call the fun()
function in src/lib.rs
.-Funsafe-code -Zsanitizer=address
flags to forbid unsafe code and enable AddressSanitizer, presumably to avoid unsafe code such as direct call to Assembly from Rust and to harden the binary from memory corruption.We discovered that we actually can still load std
even if #![no_std]
presents simply by using extern crate std. We can execute shell using std::process
or read the flag.txt
file using std::fs
.
Example:
flag: ENO{ru57_15_54f3_by_d3f4ul7}