para-code

DefCamp 문제로 풀이에 참여하였던 문제입니다.

 

Description :

I do not think that this API needs any sort of security testing as it only executes and retrieves the output of ID and PS commands.

 

해당 API는 ID, PS 명령만 출력, 실행, 검색하므로 보안 테스트가 필요하지 않다고 알려주고 있습니다.

문제 페이지로 접속 해보도록 하겠습니다.

 

 

문제 분석

 

본 문제의 페이지는 php 코드를 출력해주기 때문에 가독성을 위해 코드로 대체하였습니다.

<?php
require __DIR__ . '/flag.php';
if (!isset($_GET['start'])){
    show_source(__FILE__);
    exit;
} 

$blackList = array(
  'ss','sc','aa','od','pr','pw','pf','ps','pa','pd','pp','po','pc','pz','pq','pt','pu','pv','pw','px','py','pq','pk','pj','pl','pm','pn','pq','pf','pz','pv','pw','px','py','pq','pk','pj','pl','pm','pn','pq','pf','pz','pv','pw','px','py','pq','pk','pj','pl','pm','pn','pq','pf','pz','pv','pw','px','py','pq','pk','pj','pl','pm','pn','pq','pf','pz','pv','pw','px','py','pq','pk','pj','pl','pm','pn','pq','pf','pz','pv','pw','px','py','pq','pk','pj','pl','pm','pn','pq','pf','pz','pv','pw','px','py','pq','pk','pj','pl','pm','pn','pq','pf','pz','pv','pw','px','py','pq','pk','pj','pl','pm','pn','pq','pf','pz','pv','pw','px','py','pq','pk','pj','pl','pm','pn','pq','pf','pz','pv','pw','px','py','pq','pk','pj','pl','pm','pn','pq','pf','pz','pv','pw','px','py','pq','pk','pj','pl','pm','pn','pq','pf','pz','pv','pw','px','py','pq','pk','pj','pl','pm','pn','pq','pf','pz','pv','pw','px','py','pq','pk','pj','pl','pm','pn','pq','pf','pz','pv','pw','px','py','pq','pk','pj','pl','pm','pn','pq','ls','dd','nl','nk','df','wc', 'du'
);

$valid = true;
foreach($blackList as $blackItem)
{
    if(strpos($_GET['start'], $blackItem) !== false)
    {
         $valid = false;
         break;
    }
}

if(!$valid)
{
  show_source(__FILE__);
  exit;
}

// This will return output only for id and ps. 
if (strlen($_GET['start']) < 5){
  echo shell_exec($_GET['start']);
} else {
  echo "Please enter a valid command";
}

if (False) {
  echo $flag;
}

?>

 

해당 페이지의 코드는 크게 3가지로 보입니다.

  1. filtering
  2. shell_exec
  3. echo $flag

우선 문자열 필터링은 $blackList 변수를 선언하여 2글자인 명령어를 사용 불가하게 조치를 취한것으로 보입니다.

두 번재로 shell_exec는 start라는 파라미터를 통해 GET 방식으로 사용자에게 값을 입력받으며 명령어로 사용합니다.

이때 사용자로부터 받는 입력값은 코드상 4글자로 제한 되어 있습니다.

 

필터링 된 두 글자 명령어들과 env, set을 확인하여 추출해 보았습니다.

더보기
set.txt
0.01MB
env.txt
0.01MB
2char_cmd_result.txt
0.00MB

이때 필터링 되어 있는 명령어는 l"s" 혹은 l\s 와같이 중간에 특수문자를 입력하여 우회하였습니다.

 

 

ls result

ls 명령어를 통해 flag.php 파일이 존재한다는 것을 확인하였습니다.

 

※정리※

  • flag.php 읽기
  • 입력값 4글자
  • 공백과 "*" 사용 필수적이므로 사실상 2글자 명령어

 

 

문제 풀이

결국에는 특정 명령어를 찾는 문제였습니다.

m4라는 두 글자 짜리 명령어가 존재합니다.

view-source:http://34.159.7.96:32210/?start=m4%20*

 

해당 명령어를 사용하여 view-source 페이지에서 flag를 확인할 수 있습니다.

<?php

$flag = "791b21ee6421993a8e25564227a816ee52e48edb437909cba7e1e80c0579b6be";

?>

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

[MHSCTF] Em Dee  (0) 2022.02.20
[DefCamp CTF 21-22] casual-defence  (0) 2022.02.15
[DefCamp CTF 21-22] web-intro  (0) 2022.02.15
[Intent CTF] Graphics  (0) 2021.11.30
[Intent CTF] Etulosba  (0) 2021.11.25

web-intro

DefCamp에 참여하여 풀이에 참여한 문제입니다.

 

Description :

  1.  Are you an admin?
  2.  note: Access Denied is part of the challenge

Clinet가 admin인지에 대하여 묻고 있고 Acess Denied 또한 문제의 일부라고 알려주고 있습니다.

문제 페이지로 접속 해보도록 하겠습니다.

 

 

문제 분석

challenge page

앞서 말한 Acess Denied는 이 페이지를 두고 하는 말인것 같습니다.

개발자 도구를 사용하여 페이지 소스, 네트워크 등을 확인해 보았지만 해당 페이지 하나와 cookie값만 확인 되었습니다.

이때 session이라고 적힌 쿠키의 형태를 보고 jwt인 느낌을 강하게 받아 복호화를 진행하였습니다.

 

jwt decrypt

복호화 결과 "logged_in": false 값을 보고 jwt라는 확신이 들었습니다.

"Are you an admin?" "logged_in": false

위 두가지를 통해 false 대신 admin 혹은 True 값을 시도해 보았으나 맞지 않았습니다.

그렇기에 jwt crack을 사용하여 사전 대입 공격을 수행하였습니다.

 

jwt-cracker

 

secret key로 password가 나온것을 확인할 수 있습니다. 

이를 사용하여 인증해보도록 하겠습니다.

 

 

문제 풀이

authentication

 

secret key를 사용하여 새로운 session값을 얻었습니다.

획득한 값을 cookie에 입력해주면 FLAG가 출력 됩니다.

 

You are logged in! CTF{66bf8ba5c3ee2bd230f5cc2de57c1f09f471de8833eae3ff7566da21eb141eb7}

 

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

[DefCamp CTF 21-22] casual-defence  (0) 2022.02.15
[DefCamp CTF 21-22] para-code  (0) 2022.02.15
[Intent CTF] Graphics  (0) 2021.11.30
[Intent CTF] Etulosba  (0) 2021.11.25
[Intent CTF] Careers  (0) 2021.11.22

당신의 문제는 무엇입니까?
당신의 "소중한" CTF에서 내 아름답고 혁신적인 페이지를 어떻게 승인하지 않았습니까?
모든 작업이 완료되었습니다. 아마도 나는 그래픽을 추가할 수 있을 것입니다.

 

해당 URL에 접속할 경우 다음과 같이 강의 시간표 같은 항목을 확인할 수 있습니다.

그 외에는 별다른 내용이 없기에 웹 프록시툴을 사용하여 패킷을 잡아 확인해 보았습니다.

 

POST /api/v1/ HTTP/2
Host: graphics.chal.intentsummit.org
Cookie: intent-ctf-session=2a914d13fe5006489d427bf984179053
Content-Length: 149
Sec-Ch-Ua: "Chromium";v="95", ";Not A Brand";v="99"
Accept: */*
Content-Type: application/json
Sec-Ch-Ua-Mobile: ?0
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36
Sec-Ch-Ua-Platform: "Windows"
Origin: https://graphics.chal.intentsummit.org
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: https://graphics.chal.intentsummit.org/
Accept-Encoding: gzip, deflate
Accept-Language: he-IL,he;q=0.9,en-US;q=0.8,en;q=0.7

{"operationName":"ExampleQuery","variables":{},"query":"query ExampleQuery {\n  talks {\n    time\n    title\n    speaker\n    __typename\n  }\n}\n"}

몇번의 검색을 통해 밑에 있는 구문이 GQL이라는 것을 알아냈고 이문제는 GQL을 이용하는 문제임을 알게 되었습니다.

 

 

{"errors":[{"message":"Cannot query field \"secret\" on type \"Query\". Did you mean \"_secret\"?","extensions":{"code":"GRAPHQL_VALIDATION_FAILED","exception":{"stacktrace":["GraphQLError: Cannot query field \"secret\" on type \"Query\". Did you mean \"_secret\"?","    at Object.Field (/usr/src/app/node_modules/graphql/validation/rules/FieldsOnCorrectTypeRule.js:48:31)","    at Object.enter (/usr/src/app/node_modules/graphql/language/visitor.js:323:29)","    at Object.enter (/usr/src/app/node_modules/graphql/utilities/TypeInfo.js:370:25)","    at visit (/usr/src/app/node_modules/graphql/language/visitor.js:243:26)","    at validate (/usr/src/app/node_modules/graphql/validation/validate.js:69:24)","    at validate (/usr/src/app/node_modules/apollo-server/node_modules/apollo-server-core/dist/requestPipeline.js:185:39)","    at processGraphQLRequest (/usr/src/app/node_modules/apollo-server/node_modules/apollo-server-core/dist/requestPipeline.js:90:34)","    at processTicksAndRejections (node:internal/process/task_queues:96:5)","    at async processHTTPRequest (/usr/src/app/node_modules/apollo-server/node_modules/apollo-server-core/dist/runHttpQuery.js:187:30)"]}}}]}

query injection을 시도한 결과 'secret'이 의심스러워 보입니다.

 

 

{"operationName":"ExampleQuery","variables":{},"query":"query ExampleQuery { _secret { flag } }\n"}

이를 이용하여 쿼리를 재구성 해 보았습니다.

 

그 결과 INTENT{d1d_y0u_m34n_flag}를 획득할 수 있었습니다.

 

GraphQL에 대한 자세한 내용은 https://ravidusash.tistory.com/148 이곳에서 다루도록 하겠습니다.

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

[DefCamp CTF 21-22] para-code  (0) 2022.02.15
[DefCamp CTF 21-22] web-intro  (0) 2022.02.15
[Intent CTF] Etulosba  (0) 2021.11.25
[Intent CTF] Careers  (0) 2021.11.22
[Intent CTF] Door (un)Locked  (0) 2021.11.22

우리 스파이가 Etulosba CDN의 소스 코드를 훔치는 데 성공했습니다.
해당 서버에서 플래그를 가져오려면 여러분의 도움이 필요합니다.

주어진 main.js 파일 먼저 확인해보도록 하겠습니다.

 

 

main.js 파일입니다.

const fs = require("fs");
const path = require("path");
const express = require("express");

const server = express();

server.get("/", function (req, res) {
    res.end("<html><body>etulosba</body></html>");
});

server.get("/files/images/:name", function (req, res) {
    if (req.params.name.indexOf(".") === -1) {
        return res.status(400).json({ error: "invalid file name" });
    }

    res.sendFile(__dirname + path.join("/files/images/", req.params.name));
});

server.get("/files/binary/:name", function (req, res) {
    if (req.params.name.indexOf(".") !== -1) {
        return res.status(400).json({ error: "invalid file name" });
    }

    res.sendFile(path.resolve(__dirname, "/files/binary/", req.params.name));
});

fs.writeFileSync(path.join(__dirname, "flag.name"), process.env.FLAG_NAME);
fs.writeFileSync(path.join("/tmp", process.env.FLAG_NAME), process.env.FLAG);

server.listen(process.env.HTTP_PORT);

 

특정 주소로부터 flag.name 파일을 가져와야 하고 후에 값을 사용하여 /tmp 안에 있는 플래그 파일을 가져올 수 있습니다.

 

 

think1  이는 LFI를 이용하는 문제로 보입니다. 우선적으로 /files/images/에서 파일을 획득해야됩니다.

약간의 조건이 걸려 있습니다. 

/files/images/:name

위 형식을 유지해야 하며 indexof의 결과 값 즉, 일치하는 결과 값이 없어 -1이 나오게 하면 error을 뿜습니다.

 

 

때문에 아래와 같이 위 형식을 유지하되 index of('.')를 우회 하도록 하여야합니다.

/files/images/%2E%2E%2F%2E%2E%2Fflag%2Ename

그럴 경우 txt 하나를 획득하게 됩니다.

 

 

 

 

think2  이제 폴더명을 획득했으니 위와 유사한 방식으로 /files/binary/에서 파일을 획득해야됩니다.

/tmp 파일 안에 있다고 위에서 언급했으니 다음과 같은 url을 입력해줍니다.

/files/binary%2Ftmp%2Fimaflagimaflag

그 결과 아래와 같이 flag를 획들할수 있었습니다.

 

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

[DefCamp CTF 21-22] web-intro  (0) 2022.02.15
[Intent CTF] Graphics  (0) 2021.11.30
[Intent CTF] Careers  (0) 2021.11.22
[Intent CTF] Door (un)Locked  (0) 2021.11.22
[2021 hspace] Baby_Crypto  (0) 2021.05.07

[Intent CTF] Web 카테고리 두번째 문제입니다.

URL에 먼저 접속해보도록 하겠습니다.

 

 

Get more Information, More은 특별하게 없어 보이고 우측 상단에 Careers에 파일을 업로드하는 기능이 존재합니다.

think1 file-upload를 통해 공격이 진행되는 것으로 짐작됩니다.

 

 

txt 형식만 사용하여 이력서를 구성하고 zip 파일로 만들어 업로드 하십시오.

txt 파일을 zip으로 만들어 업로드 하라고 하니 일단 업로드 해보도록 하겠습니다.

 

 

zip 파일을 업로드하자 URL을 줍니다. 접속해보도록 하겠습니다.

 

 

업로드한 zip이 풀려 txt 파일만을 다운 받을수 있도록 서비스가 제공되고 있습니다.

think2 이 문제에서 서버는 업로드된 zip파일의 압축을 해제합니다. 심볼릭 링크를 사용하여 압축할(zip Symlic) 경우 서버 파일 시스템에서 압축을 해제해도 내가 필요한 파일에 대한 링크가 계속 유지될 것 같습니다.

 

제작해보도록 하겠습니다. 페이로드 제작 방식은 다음과 같습니다.

ln -s /flag test.txt
zip --symlinks symtest.zip *

결과 symtest.zip 파일이 생성됩니다.

 

symtest.zip 파일을 업로드 해보도록 하겠습니다.

test 파일에서 flag를 획득하는것을 확인할 수 있습니다.

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

[Intent CTF] Graphics  (0) 2021.11.30
[Intent CTF] Etulosba  (0) 2021.11.25
[Intent CTF] Door (un)Locked  (0) 2021.11.22
[2021 hspace] Baby_Crypto  (0) 2021.05.07
[DiceCTF] web/Web Utils (2)  (0) 2021.03.09

[Intent CTF] Web 카테고리 첫번째 문제입니다.

일부 연구원은 CTF용 웹사이트를 배포하기 시작했지만 플래그를 숨기려고 할 때 정의된 정책에 문제가 발생했습니다.
약한 링크를 찾을 수 있습니까?

think1 정책을 통해서 해당 서버를 보호하고 있으며 정책중에 문제가 있어 취약한 부분을 공격하는 문제인듯 합니다.

 

추가로 제공된 ha.cfg 파일을 확인해보도록 하겠습니다. 내용은 아래와 같습니다.

global
    daemon
defaults  
    mode    http
    timeout  client  50000
    timeout  server  50000
    timeout  connect 50000
frontend web 
    bind *:8000  
    http-request deny if { path_beg /flag }
    http-request deny if { path,url_dec -m reg ^.*/?flag/?.*$ }
    default_backend websrvs
backend websrvs 
    http-reuse always
    server srv1 flask:5000

 

구성과 내용을 기반으로 검색해 보았을 때 ha.cfg 파일은 로드밸런싱 및 보안을 위한 haproxy 파일로 보입니다.

http-request deny로 몇가지 제약사항 필터링이 걸린것을 확인 할수 있습니다.

 

think2 해당 주소 /flag로 접근하기 위해서는 필터링을 무력화해야만 합니다.

필터링 조건들을 한번 살펴 보겠습니다.

http-request deny if { path_beg /flag }

/flag 문자열로 시작되는 요청은 차단된다는 의미입니다.

http-request deny if { path,url_dec -m reg ^.*/?flag/?.*$ }

url을 디코딩한 후에 나오는 값이 정규표현식 ^.*/?flag/?.*$ 문자와 같을 경우 모든 요청을 차단합니다.

이곳에서 자세히 봐야 할것이 있습니다. 정규표현식이 잘못됬다는 것입니다.

표현할때 역슬래쉬로 처리를 해줘야 동작합니다. 

/? -> \/\?

 

think3 /flag가 정확히 어떤주소에 있는지 살펴보겠습니다.

다행히도 url:port 바로 뒤에 /flag가 존재하며 정책에 의해 접근이 불가능 한것을 확인할 수 있습니다.

 

think4 필터링을 우회해보도록 하겠습니다.

/flag로 접속할경우 보안 정책에 의해 403 Forbidden이 Response 값으로 나오게 됩니다.

/flag를 1./flag로 시작하면 안된다. 2. url deocoding한 값이 제시된 정규표현식과 일치해서는 안된다는 조건에 의거하여 /./../flag로 변경하도록 하겠습니다.

 

 

. 때문에 403 Forbidden이 뜨고 있습니다.

정규표현식에서 . 의 경우 line terminators를 이용하여 우회가 가능합니다.

%0a를 사용해보도록 하겠습니다.

 

 

200 정상적으로 Response가 나타나는 것을 확인할수 있습니다.

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

[Intent CTF] Etulosba  (0) 2021.11.25
[Intent CTF] Careers  (0) 2021.11.22
[2021 hspace] Baby_Crypto  (0) 2021.05.07
[DiceCTF] web/Web Utils (2)  (0) 2021.03.09
[DiceCTF] web/Web Utils (1)  (0) 2021.02.23

+ Recent posts