Web
Personnel
challange description
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
flag = open("flag.txt").read()
users = open("users.txt").read()
users += flag
@app.route("/", methods=["GET", "POST"])
def index():
if request.method == "GET":
return render_template("lookup.html")
if request.method == "POST":
name = request.form["name"]
setting = int(request.form["setting"])
if name:
if name[0].isupper():
name = name[1:]
results = re.findall(r"[A-Z][a-z]*?" + name + r"[a-z]*?\n", users, setting)
results = [x.strip() for x in results if x or len(x) > 1]
return render_template("lookup.html", passed_results=True, results=results)
The name is concatenated and used as regex for search for a pattern so by entering the name as |flag{.*}|
It will return all the strings any string starting with a capital letter followed by any number of small letters or flag format or word consisting of small letters
query results
flag{f0e659b45b507d8633065bbd2832c627}
Reverse
babyrev
challange description
looking at the elf file
1
2
3
4
5
6
7
8
9
10
11
12
13
v6 = __readfsqword(0x28u);
printf("Welcome to baby's first rev! :>\nPlease enter your username: ");
__isoc99_scanf("%s", s1);
printf("Please enter your password: ");
__isoc99_scanf("%s", v5);
if ( strcmp(s1, "bossbaby") )
{
printf("%s? I don't know you... stranger danger...", s1);
exit(0);
}
puts("You're almost there!");
if ( (unsigned int)sub_12AD(v5) == 38 )
printf("You're boss baby!");
username is babyboss
and the password is passed to Subroutine sub_12AD
The important part of this function is a call to function sub_1208 + 1
then it compares the data stored at dword_4020
with the password
1
2
3
4
5
6
7
8
9
((void (__fastcall *)())((char *)&sub_1208 + 1))();
for ( i = 0; ; ++i )
{
v4 = i;
if ( v4 >= strlen(s) )
break;
if ( dword_4020[i] == *((_DWORD *)v11 + i) )
++v8;
}
this address wasn’t recognized as code so you have to make a function at this location
1
2
3
4
5
6
7
8
__int64 __fastcall sub_120D(const char *a1, __int64 a2)
{
int i; // [rsp+1Ch] [rbp-14h]
for ( i = 0; i < strlen(a1); ++i )
*(_DWORD *)(4LL * i + a2) = (a1[i] << ((char)i % 7)) + i * i;
return a2;
}
extract bytes at dword_4020
and reverse the encryption done by sub_120D
1
2
3
4
5
6
7
8
9
10
11
12
13
14
arr = [0x66, 0x0D9, 0x188, 0x341, 0x7C0, 0x6F9, 0x18A4, 0x95, 0x10A,
0x1D5, 0x37C, 0x3A9, 0x7B0, 0x1969, 0x127, 0x1A3, 0x1C4, 0x2B9,
0x754, 0x889, 0x0F50, 0x1F0, 0x254, 0x2D9, 0x558, 0x571, 0x924,
0x1019, 0x342, 0x3AD, 0x508, 0x6E9, 0x0A30, 0x10E1, 0x1284,
0x500, 0x5D2, 0x74D,]
flag = ''
for i in range(len(arr)):
temp = arr[i] - (i * i)
temp = temp >> (i % 7)
flag += chr(temp)
print(flag)
flag{7bdeac39cca13a97782c04522aece87a}
Mobile
OTP Vault
challange description
opening APK at JADX-GUI and looking at the main activity
1
2
3
4
5
6
7
8
9
10
11
12
13
package com.otpvault;
import com.facebook.react.ReactActivity;
import com.facebook.react.ReactActivityDelegate;
import com.facebook.react.ReactRootView;
/* loaded from: classes.dex */
public class MainActivity extends ReactActivity {
@Override // com.facebook.react.ReactActivity
protected String getMainComponentName() {
return "OTPVault";
}
the main activity inherits from ReactActivity
this means the apk build using react-native
running apktool to extract all files from APK
1
apktool d OTPVault.apk
looking at the code at OTPVault.ap/assets/index.android.bundle
a search for otp then copy a few lines and prettify it
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function O() {
var n;
(0, e.default)(this, O);
for (var o = arguments.length, u = new Array(o), l = 0; l < o; l++) u[l] = arguments[l];
return (n = b.call.apply(b, [this].concat(u))).state = {
output: 'Insert your OTP to unlock your vault',
text: ''
}, n.s = 'JJ2XG5CIMFRWW2LOM4', n.url = 'http://congon4tor.com:7777', n.token = '652W8NxdsHFTorqLXgo=',
n.getFlag = function() {
var e, o;
return t.default.async(function(u) {
for (;;) switch (u.prev = u.next) {
case 0:
return u.prev = 0, e = {
headers: {
Authorization: 'Bearer KMGQ0YTYgIMTk5Mjc2NzZY4OMjJlNzAC0WU2DgiYzE41ZDwN'
}
}, u.next = 4, t.default.awrap(p.default.get(n.url + "/flag", e));
case 4:
o = u.sent, n.setState({
output: o.data.flag
// }), u.next = 12;
sending the same request using postman
postman request
flag{5450384e093a0444e6d3d39795dd7ddd}
Secure Notes
challange description
opening the APK in JADX-GUI and looking at login activity
the APK takes a pin code and repeats it 4 times then use it as a key for AES encryption to decrypt the database
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public void onClick(View view) {
try {
C0940d.m156k(this.f2153b.getText().toString() + this.f2153b.getText().toString() + this.f2153b.getText().toString() + this.f2153b.getText().toString(), new File(this.f2154c.getPath()), new File(LoginActivity.this.getCacheDir(), "notes.db"));
LoginActivity.this.startActivity(this.f2155d);
} catch (C0947a unused) {
Toast.makeText(LoginActivity.this.getApplicationContext(), "Wrong password", 0).show();
}
}
public static void m156k(String str, File file, File file2) {
try {
SecretKeySpec secretKeySpec = new SecretKeySpec(str.getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(2, secretKeySpec);
FileInputStream fileInputStream = new FileInputStream(file);
byte[] bArr = new byte[(int) file.length()];
fileInputStream.read(bArr);
byte[] doFinal = cipher.doFinal(bArr);
FileOutputStream fileOutputStream = new FileOutputStream(file2);
fileOutputStream.write(doFinal);
fileInputStream.close();
fileOutputStream.close();
} catch (IOException | InvalidKeyException | NoSuchAlgorithmException | BadPaddingException | IllegalBlockSizeException | NoSuchPaddingException e) {
throw new C0947a("Error encrypting/decrypting file", e);
}
}
writing script to brute force all keys and save the decrypted File
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.WeakHashMap;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;
import java.nio.file.Path;
import java.nio.file.Paths;
public class Main {
public static void main(String args[]) {
for (int i1 = 0; i1 < 10; i1++) {
for (int i2 = 0; i2 < 10; i2++) {
for (int i3 = 0; i3 < 10; i3++) {
for (int i4 = 0; i4 < 10; i4++) {
String code = Integer.toString(i1) + Integer.toString(i2) + Integer.toString(i3) + Integer.toString(i4);
String str = code + code + code + code;
String file = "./db.encrypted";
String file2 = "./" + code + ".db";
// System.out.println("Trying value: " + code);
try {
SecretKeySpec secretKeySpec = new SecretKeySpec(str.getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(2, secretKeySpec);
// FileInputStream fileInputStream = new FileInputStream(file);
// byte[] bArr = new byte[(int) file.length()];
// fileInputStream.read(bArr);
Path path = Paths.get("./db.encrypted");
byte[] bArr = java.nio.file.Files.readAllBytes(path);
// System.out.println("Found value: " + bArr.length);
byte[] doFinal = cipher.doFinal(bArr);
FileOutputStream fileOutputStream = new FileOutputStream(file2);
fileOutputStream.write(doFinal);
// fileInputStream.close();
fileOutputStream.close();
System.out.println("Found value: " + code);
break;
} catch (IOException | InvalidKeyException | NoSuchAlgorithmException | BadPaddingException | IllegalBlockSizeException | NoSuchPaddingException e) {
// System.out.println(e);
}
}
}
}
}
}
}
this script will generate many files and by running file command only one of them will be defined as JSON with correct pin 5732
flag{a5f6f2f861cb52b98ebedcc7c7094354}
Click Me
challange description
opening the apk in JADX-GUI and looking at the Main activity
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public final void cookieViewClick(View view) {
int i = this.CLICKS + 1;
this.CLICKS = i;
if (i >= 13371337) {
this.CLICKS = 13371337;
}
((TextView) findViewById(C0574R.C0577id.cookieCount)).setText(String.valueOf(this.CLICKS));
}
public final void getFlagButtonClick(View view) {
Intrinsics.checkNotNullParameter(view, "view");
if (this.CLICKS == 99999999) {
Toast.makeText(getApplicationContext(), getFlag(), 0).show();
return;
}
Toast.makeText(getApplicationContext(), "You do not have enough cookies to get the flag", 0).show();
}
it is not possible to get a 99999999 click
using apktool
1
apktool d click_me.apk
and change the value 99999999 to 5 at smali bytecode and set extractNativeLibs
as true
at AndroidManifest
then compile the patched APK
1
apktool.exe b click_me/ -o flag.apk
then create signature key and sign the APK to run it
1
2
3
keytool -genkey -v -keystore my-release-key.keystore -alias alias_name -keyalg RSA -keysize 2048 -validity 10000
jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore my-release-key.keystore flag.apk alias_name
run apk, click at the cookie 5 time at click get flag button
flag{849d9e5421c59358ee4d568adebc5a70)
Malware
Otto’s It
challange description
DetectItEasy identify the file as an AutoIt script
DetectItEasy
using AutoIt extractor to get the script
autoit extractor
Analyzing the script
The script is obsticated but from the description you can think about clip board as malware might change the value copied to mactch the attacker wallet address and thatis how he steal the money
Seach for Clipboard you will find a function read clipBoard and compare it to some varibles but thier value isn’t clear so i modified the code after each variable to pop up a message box with it value ex
MsgBox(0,"",$ckkgdnbk_rowmg_zlwyizjakm)
MsgBox(0,"",$var_2025)
MsgBox(0,"",$var_2571)
MsgBox(0,"",$rmkily_bsqta)
and cmpiled the file and after few message box here is the flag flag
flag{f4bc6d0bfcbf128c97490e392a39842b}
USB Drive
challange description
Open the LNK as a text file found a lot of empty lines and at the end, this command appears to fetch some data from a URL
1
CMD<ttps://tinyurl.com/a7ba6ma
the link point to some encoded data stage2
decode it from base 32
base32 cyberchef
The decoded file is a DLL.
The analysis reveals that DllMain will show the flag at a message box
run the dll
1
rundll32.exe stage2.dll,DllMain
flag
flag{0af2873a74cfa957ccb90cef814cfe3d}
Miscellaneous
One Mantissa Please
challange description
from this link javascripts number type 9007199254740992 IS equal to 9007199254740993
flag{3a78300a68de2a1210c9e3726c3cb87a}
To Be And Not To Be
challange description
in javascript NaN != NaN
flag{7ecfb3bf076a6a9635f975fe96ac97fd}
Steganography
Ostrich
challange description
The script will load the image and loop over each char of the flag to find a random pixel and multiply the char of the flag with the third color value of the pixel the store then result in the pixel and save the image
In the end, all images are converted to one apng image
Writing a script that will loop over each frame of the apng and found the different pixel and get the flag
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import imageio
from PIL import Image, GifImagePlugin
from Crypto.Util.number import long_to_bytes as l2b, bytes_to_long as b2l
import random
from apng import APNG
filenames = []
flag = 'x' * 32
orig_filename = "ostrich.jpg"
orig_image = Image.open(orig_filename)
pixels = orig_image.load()
width, height = orig_image.size
images = []
flag = ''
im = APNG.open("result.apng")
i = 0
for frame, control in im.frames:
frame.save("frame.png")
png = Image.open("frame.png")
png_pixels = png.load()
for x in range(width):
for y in range(height):
pixel = list(png.getpixel((x, y)))
if pixel[2] == 0:
if pixel[0] != orig_image.getpixel((x,y))[0]:
b = [pixel[0]]
if pixel[1] != orig_image.getpixel((x,y))[1]:
b.append(pixel[1])
l = b2l(bytes(b))
flag += chr(int(l / orig_image.getpixel((x,y))[2]))
print(flag)
flag{d3a5b80f96a3ce0dd0aedbefbc6b1fa1}