sudo ./run.sh -d dlink dcs932lb1_v200_b6.bin

/bin/alphapdnipcauserverify() 함수 분석을 진행했던 것으로 보아, 인증 관련 기능을 포함할 가능성이 높음/etc_ro/web/cgi/system.cgiAdminPassword, AdminID 값을 다루고 있는 것으로 보아, 관리 인터페이스 관련 가능성 있음/sbin/firewall.sh/bin/gcmdv5 = fopen("/var/run/nvramd.pid", "r");
if ( !v5 ) {
trace(16, "waiting for nvram_daemon", v6);
Sleep(1);
if ( v4 >= 15 ) {
trace(0, "please execute nvram_daemon first!", v8);
return -1;
}
}
/var/run/nvramd.pid 파일이 존재하지 않으면 최대 15초 동안 기다린 후 실행 종료nvram은 환경 설정 값을 저장하는 비휘발성 메모리(NVRAM)와 관련!v10 = nvram_bufget(0, "SecondHTTPPortEnable");
v11 = (_BYTE *)nvram_bufget(0, "SecondHTTPPort");
if ( v10 && !strcmp(v10, "3") && v11 && *v11 )
v3 = atoi(v11);
SecondHTTPPortEnable이 3으로 설정되어 있고, SecondHTTPPort 값이 존재하면 해당 포트 사용nvram_bufget()을 통해 가져오는 값이 올바르게 검증되지 않으면 취약점이 발생할 가능성sub_4069B4(15, sub_406938);
sub_4069B4(2, sub_406938);
signal(13, 1);
sub_4069B4() 함수는 신호 핸들링 관련 함수일 가능성이 높음signal(13, 1); → SIGPIPE 시그널 무시 (SIGPIPE는 파이프가 끊어졌을 때 발생하는 시그널)if ( websStartupServer(v3) >= 0 ) {
trace(0, "Running at address %s:%d\n", &websSrvIpAddr);
websParaOpen();
websSetFormOpen();
websEnableErrorMessage();
websStartAuthentication();
httpd_main();
websEndAuthentication();
websDisableErrorMessage();
websSetFormClose();
websParaClose();
websShutdownServer();
}
websStartupServer(v3) → 웹 서버 실행 (포트 v3)websStartAuthentication(); → 인증 시스템 활성화httpd_main(); → 웹 서버가 동작하는 메인 루프websEndAuthentication(); → 인증 시스템 종료websShutdownServer(); → 서버 종료int websStartAuthentication()
{
int v0; // $v0
v0 = nvram_bufget(0, "AccessControlEnable");
if ( !strcmp(v0, &word_44D1B8) )
websEnableAllUser();
return websEnableHtmlFile();
}
nvram_bufget(0, "AccessControlEnable")로 NVRAM에서 AccessControlEnable 값을 가져옴word_44D1B8과 같은 값이면 모든 사용자(websEnableAllUser())에 대해 인증을 비활성화하는 것으로 보임AccessControlEnable이 특정 값이면 인증이 필요 없을 가능성?int httpd_main()
{
int result; // $v0
int v1; // $a2
unsigned int SysInfoLong; // $v0
unsigned int v3; // $a0
unsigned int v4; // $v1
int v5; // $v0
for ( result = gotsigterm; !gotsigterm; result = usleep(1000) )
{
SysInfoLong = getSysInfoLong(56);
v3 = SysInfoLong >> 9;
v4 = SysInfoLong;
v5 = (SysInfoLong >> 9) & 1;
if ( v5 || (v5 = v3 & 1, ((v4 >> 15) & 1) != 0) || (v5 = v3 & 1, (v4 & 0x10000) != 0) )
{
if ( v5 )
{
setSysInfoLong(58, 512);
}
else if ( ((v4 >> 15) & 1) != 0 )
{
setSysInfoLong(58, 0x8000);
}
else if ( (v4 & 0x10000) != 0 )
{
setSysInfoLong(58, 0x10000);
}
websEndAuthentication();
nvram_close(0);
nvram_init(0);
websStartAuthentication();
trace(16, "reload configuration!\n", v1);
}
websSocketEventPoll();
usleep(1000);
websCgiReapChildren();
usleep(1000);
websFrameReapChildren();
usleep(1000);
websStreamReapChildren();
usleep(1000);
websTimeoutProcess();
}
return result;
}
httpd_main()은 웹 서버의 메인 루프 역할getSysInfoLong(56) 값을 확인하여 특정 비트가 설정되었는지 검사setSysInfoLong(58, 값)으로 설정하고 설정을 다시 불러옴websEndAuthentication(), nvram_close(0), nvram_init(0), websStartAuthentication()가 호출websSocketEventPoll()을 계속 실행하여 웹 서버가 요청을 처리하도록 함int __fastcall getSysInfoLong(int a1)
{
int v2; // $s1
int v4; // [sp+18h] [-8h] BYREF
v2 = open("/dev/gpio", 0);
v4 = 0;
if ( v2 >= 0 )
{
ioctl(v2, (a1 << 8) | 0x20080, &v4);
close(v2);
}
return v4;
}
/dev/gpio 디바이스 파일을 오픈ioctl(v2, (a1 << 8) | 0x20080, &v4);a1을 왼쪽으로 8비트 시프트한 후 0x20080과 OR 연산ioctl() 호출을 통해 GPIO에서 값을 가져옴v4에 저장되며 반환GPIO 인터페이스를 직접 조작할 수 있으려나
int websCgiReapChildren()
{
int result; // $v0
int i; // $s2
int *v2; // $s1
int v3; // $s0
const char *v4; // $a1
int v5; // $a3
int v6; // [sp+18h] [-8h] BYREF
result = dword_491720;
for ( i = 0; dword_491720 >= i; result = dword_491720 < i )
{
while ( 1 )
{
v2 = *(int **)(4 * i + dword_4934A0);
if ( v2 )
{
v3 = *v2;
if ( !websReapChildren(v2[1], (int)&v6) )
break;
}
result = dword_491720 < ++i;
if ( dword_491720 < i )
return result;
}
websConnClose(v3, 200);
v4 = "child(%d) exited, status=%d\n";
v5 = (unsigned __int16)(v6 & 0xFF00) >> 8;
if ( (v6 & 0x7F) != 0 && (v5 = v6 & 0x7F, v4 = "child(%d) killed (signal %d)\n", (unsigned __int8)v6 == 127) )
trace(16, (int)"child(%d) stopped (signal %d)\n", v2[1], (unsigned __int16)(v6 & 0xFF00) >> 8);
else
trace(16, (int)v4, v2[1], v5);
dword_491720 = FreeEntry(&dword_4934A0, i);
free(v2);
++i;
}
return result;
}
websReapChildren(v2[1], (int)&v6)를 호출하여 자식 프로세스 종료 여부 확인websConnClose(v3, 200); 실행trace(16, ...);를 통해 종료 로그 남김FreeEntry(&dword_4934A0, i);를 통해 목록에서 제거BOOL __fastcall websReapChildren(int a1, int a2)
{
return waitpid(a1, a2, 1) != a1;
}
waitpid(a1, a2, 1)
a1 프로세스의 상태를 확인하고, 종료 여부를 반환1 옵션은 Non-blocking 모드 (즉, 기다리지 않고 바로 반환)return waitpid(a1, a2, 1) != a1;
waitpid()의 반환값이 a1과 같지 않다면 TRUE 반환int __fastcall setSysInfoLong(int a1, int a2)
{
int result; // $v0
int v5; // $s2
int v6; // [sp+18h] [-8h] BYREF
result = open("/dev/gpio", 0);
v5 = result;
v6 = a2;
if ( result >= 0 )
{
ioctl(result, (a1 << 8) | 0x20081, &v6);
return close(v5);
}
return result;
}
open("/dev/gpio", 0);
/dev/gpio 파일을 열어 GPIO 장치에 접근ioctl(result, (a1 << 8) | 0x20081, &v6);
a1 값을 왼쪽으로 8비트 이동(shift) 후, 0x20081과 OR 연산v6 = a2;를 사용해 GPIO 값을 변경close(v5);
CameraName=%%CameraName();%%
Location=%%Location();%%
AdminID=%%AdminID();%%
AdminPassword=%%AdminPassword();%%
LEDControl=%%LEDControl();%%
SnapshotURLAuthentication=%%SnapshotURLAuthentication();%%
%%Function();%% 형태의 매크로(템플릿 엔진) 사용AdminID, AdminPassword) 유출 가능성curl -X GET http://<대상 ip>/cgi/system.cgi
수정되지 않은 기본값(Default Credentials)이 존재할 가능성
- 일부 장치에서는 기본값(admin/admin)이 그대로 저장됨
- /etc_ro/Wireless/RT2860AP/RT2860_default_novlan 파일에도 Password=admin으로 설정되어 있음
해당 값이 nvram_bufget()에서 로드될 가능성
- nvram_bufget(0, "AdminPassword") 등을 사용하여 불러올 가능성이 있음
- 이전 alphapd 분석에서 nvram_bufget()을 통해 설정을 불러오는 부분이 확인됨
LEDControl & SnapshotURLAuthentication 조작 가능성LEDControl 필드 변경을 통해 물리적 LED 동작을 조작 가능curl -X POST http://<대상 ip>/cgi/system.cgi -d "LEDControl=off"
SnapshotURLAuthentication를 비활성화하면 인증 없이 스트림 접근 가능curl -X POST http://<target_ip>/cgi/system.cgi -d "SnapshotURLAuthentication=0"
http://<target_ip>/image/jpeg.cgi
iptables 규칙 초기화 (iptablesAllFilterClear())
iptables -F -t filter)INPUT, OUTPUT, FORWARD 기본 정책을 ACCEPT로 설정방화벽 초기화 (init())
방화벽 종료 (fini())
iptablesAllFilterClear() 문제점ACCEPT로 설정iptables -P INPUT ACCEPT
iptables -P OUTPUT ACCEPT
iptables -P FORWARD ACCEPT
firewall.sh init)하면 모든 트래픽이 필터링 없이 통과 가능.DMZ_CHAIN 및 PORT_FORWARD_CHAIN 조작 가능성iptables -t nat을 이용해 포트 포워딩 및 DMZ 설정을 변경할 수 있음iptables -t nat -I PREROUTING 1 -j port_forward
iptables -t nat -I PREROUTING 2 -j DMZ
init() 함수 실행 시 우선순위 문제iptablesAllFilterRun() 및 iptablesAllNATRun()이 주석 처리되어 있음#iptablesAllFilterRun();
#iptablesAllNATRun();
init() 실행 후 방화벽 설정이 완전하지 않거나 비정상적으로 동작할 가능성 존재curl -X GET http://<대상 ip>/cgi-bin/system.cgi?cmd=firewall.sh+init
iptables -t nat -A PREROUTING -p tcp --dport 80 -j DNAT --to-destination 192.168.1.100:80
iptables -t nat -A PREROUTING -j DMZ
gcmd는 motion detection(움직임 감지)과 관련된 기능을 수행하는 것으로 판단GPIO 핀(ioctl-gcmd_read_user1_sig_flag)을 모니터링하여 동작을 감지/tmp/gotocamera/ 경로에 이미지로 저장하고, 이후 dscamd 프로세스를 호출하여 관련 데이터를 json 형식으로 전달하는 기능이 존재