[LEVEL-1] NoSQL-CouchDB
문제를 들어가면 uid와 upw를 입력할 수 있는 입력창과 Login버튼, Cancel버튼이 보인다.
개발자 도구로 입력창의 name을 보니 uid인 것을 확인하고 소스코드를 보러 넘어갔다.
굉장히 많은 코드들이 있지만 여기서 우리가 볼 것은 index.ejs와 app.js 두 개 뿐이다
<form id="form">
<div class="field">
<label class="label">uid</label>
<input class="input" type="text" placeholder="uid" name="uid" required>
</div>
<div class="field">
<label class="label">upw</label>
<input class="input" type="password" placeholder="upw" name="upw" required>
</div>
<div class="field is-grouped">
<div class="control">
<input class="button is-success" type="submit" value="Login"/>
</div>
<div class="control">
<input class="button" type="reset" value="Cancel"/>
</div>
</div>
</form>
보면 form태그 안에 위에서 말한 uid, upw 입력창, login, cancel버튼이 있는 것이 보인다
$("#form").submit(function( event ) {
event.preventDefault();
$("#form").serializeObject()
$.ajax({
type:"POST",
data: JSON.stringify($("#form").serializeObject()),
dataType:"json",
url: "/auth",
contentType:"application/json",
}).always(function(e){
const $target = document.getElementById('modal-div');
document.getElementById('modal-text').innerText = e.responseText;
openModal($target);
});
또한 form에서 입력한 내용을 'json' 데이터 타입으로 바꾸어 POST요청에 담아서 보내는 것 같다.
이번엔 app.js로 넘어가보자.
const nano = require('nano')(`http://${process.env.COUCHDB_USER}:${process.env.COUCHDB_PASSWORD}@couchdb:5984`);
const users = nano.db.use('users');
/* POST auth */
app.post('/auth', function(req, res) {
users.get(req.body.uid, function(err, result) {
if (err) {
console.log(err);
res.send('error');
return;
}
if (result.upw === req.body.upw) {
res.send(`FLAG: ${process.env.FLAG}`);
} else {
res.send('fail');
}
});
});
` req.body.uid ` 를 req로 하여 DB에서 검색해서 result에 담는다.
그리고 result.pw와 req.body.upw를 비교하여 같으면 flag를 출력하는 형식인 것 같다.
대충 문제의 코드 구성과 특징을 알아봤다. 이제 flag를 얻어보자.
먼저 이 문제에서 사용하는 couchDB에는 ` informationschema ` 같은 특수 구성요소가 존재한다
/ | 인스턴스에 대한 메타 정보를 반환합니다. |
/_all_dbs | 인스턴스의 데이터베이스 목록을 반환합니다. |
/_utils | 관리자 페이지 (Fauxton Administration Interface)로 이동합니다. |
/{DB 이름} | 지정한 데이터베이스에 대한 정보를 반환합니다. |
/{DB 이름}/_all_docs | 지정한 데이터베이스에 포함된 모든 도큐먼트를 반환합니다. |
/{DB 이름}/_find | 지정한 데이터베이스에서 JSON 쿼리에 해당하는 모든 도큐먼트를 반환합니다. |
여기서 우리가 사용할 특수 구성요소는 ` _all_docs ` 로 모든 도큐먼트를 반환하게 하여 플래그를 반환하게 할 것이다.
위 도큐먼트(플래그)를 반환하기 위해선 특수 구성요소를 uid 또는 upw에 입력해야한다.
먼저 아무 값이나 uid와 upw에 입력하고 burp suite로 프록시를 잡아보자
이렇게 하고 위 코드를 살펴보면
/* POST auth */
app.post('/auth', function(req, res) {
users.get(req.body.uid, function(err, result) {
if (err) {
console.log(err);
res.send('error');
return;
}
if (result.upw === req.body.upw) {
res.send(`FLAG: ${process.env.FLAG}`);
} else {
res.send('fail');
}
});
});
이 부분에서 result.upw와 req.body.upw를 비교하여 동일할 경우 flag를 출력하는 것으로 보인다. (error가 나지 않을 경우)
그렇다면 uid에 특수 구성요소(_all_docs)를 넣어주면 우선 에러가 나오지는 않는다.
그리고 upw를 공백으로 만들면 ` result.upw === undefined ` 가 되므로 통과가 되서 특수 구성요소를 통해 플래그가 출력될 것이다.
이렇게 uid에 특수 구성요소를 넣고 upw를 지워준다.
여기서 주의할 점이 "upw":"123"만 지우면 안되고 uid뒤에 붙은 ','도 지워줘야 플래그가 출력된다.