Skip to content

simula tr069.md

Luca Olivetti edited this page Aug 9, 2020 · 6 revisions

simular el servidor tr-069 de digi para establecer la password de admin del router

La comunicación siempre es activada desde el router:

  1. El router conecta con el servidor
  2. El servidor envía comandos al router en la respuesta (o nada si no hay más comandos para ejecutar)
  3. El router hace una nueva petición con el resultado del comando y se repite el proceso desde el punto 2

Aquí puedes encontrar la documentación completa del protocolo (solo para estómagos fuertes) y más información.

Nuestro objetivo es enviar un comando que ajuste la password de admin.

Para ello creamos un servidor ficticio con lighttpd y stunnel. Prefiero usar stunnel en lugar de configurar el https en lighttpd así es más fácil examinar la comunicación con wireshark.

configuración de lighttpd

En lighttpd habilitamos cgi y accesslog, creando los enlace simbolicos correspondientes de /etc/lighttpd/conf-enabled/ a /etc/lighttpd/conf-available/, después en /etc/lighttpd/conf-available/10-cgi.conf ponemos

# /usr/share/doc/lighttpd/cgi.txt

server.modules += ( "mod_cgi" )

$HTTP["url"] =~ "^/.*" {
        cgi.assign = ( "/simula" => "" )
        alias.url = ( "" => "/etc/lighttpd/simula")
}

de esta manera cualquier petición al servidor ejecutará el script /etc/lighttpd/simula que crearemos con el siguiente contenido (y haremos ejecutable con chmod +x /etc/lighttpd/simula)

OJO este script es potencialmente muy peligroso, por lo que se tiene que asegurar que lighttpd no sea accesible desde el exterior.

#!/bin/bash


eval $HTTP_COOKIE
if [ -z $session ] ; then
   session=$(date +'%F-%T')
   mkdir /tmp/acs/$session
fi  

if [ -f /tmp/acs/${session}/status ] ; then
  status=$(cat /tmp/acs/${session}/status)
else
  status=1
fi  

if [ ! -f /etc/lighttpd/resp${status} ] ; then
  exit
fi
  
echo "Content-Type: text/xml"
[ -n "$session" ] && echo "Set-Cookie: session=$session"
echo "" 
cat /dev/stdin > /tmp/acs/${session}/req${status}
cat /etc/lighttpd/resp${status}

status=$(($status+1))
echo $status > /tmp/acs/${session}/status

Habrá que crear el directorio /tmp/acs y que lighttpd pueda escribir en el chown www-data /tmp/acs. El script, por cada nueva sesión, creará un directorio en /tmp/acs donde pondrá las peticiones del router (que son la respuesta al comando anterior del servidor) req1, req2, req3, ... Si existe el fichero correspondiente al paso (/etc/ligttpd/resp1,/etc/lighttpd/resp2, etc.) lo envía al router.

Los ficheros tendrán este contenido:

/etc/lighttpd/resp1

<SOAP-ENV:Envelope xmlns:SOAP="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:cwmp="urn:dslforum-org:cwmp-1-0" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<SOAP-ENV:Header>
<cwmp:ID SOAP:mustUnderstand="1">1</cwmp:ID>
<cwmp:NoMoreRequest>0</cwmp:NoMoreRequest>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<cwmp:InformResponse><MaxEnvelopes>1</MaxEnvelopes></cwmp:InformResponse></SOAP-ENV:Body></SOAP-ENV:Envelope>

/etc/lighttpd/resp2

<SOAP-ENV:Envelope xmlns:SOAP="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:cwmp="urn:dslforum-org:cwmp-1-0" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<SOAP-ENV:Header>
<cwmp:ID SOAP:mustUnderstand="1">1</cwmp:ID>
<cwmp:NoMoreRequest>0</cwmp:NoMoreRequest>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<cwmp:SetParameterValues>
<ParameterList>
<ParameterValueStruct><Name>InternetGatewayDevice.DeviceInfo.X_ZTE-COM_AdminAccount.Password</Name><Value xsi:type="xsd:string">xxxxxxxxxxx</Value></ParameterValueStruct>
<ParameterValueStruct><Name>InternetGatewayDevice.DeviceInfo.X_ZTE-COM_AdminAccount.Enable</Name><Value xsi:type="xsd:boolean">1</Value></ParameterValueStruct>
</ParameterList>
<ParameterKey/>
</cwmp:SetParameterValues>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

(en lugar de xxxxxxxxxx hay que poner la password que quereis, la password debe contener por lo menos un numero, una letra mayuscula, una minuscula y un simbolo, y debe ser 8 caracteres o más, si no el router no la acepta).

/etc/lighttpd/resp3 debe existir pero es vacío.

La respuesta del segundo comando (resp2) estará en la tercera petición (req3) y es donde comprobaremos si el comando ha tenido éxito. Si es Status 0 ha funcionado

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:cwmp="urn:dslforum-org:cwmp-1-0"><SOAP-ENV:Header><cwmp:ID SOAP-ENV:mustUnderstand="1">1</cwmp:ID>
</SOAP-ENV:Header>
<SOAP-ENV:Body><cwmp:SetParameterValuesResponse><Status>0</Status>
</cwmp:SetParameterValuesResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

en caso de error

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:cwmp="urn:dslforum-org:cwmp-1-0"><SOAP-ENV:Header><cwmp:ID SOAP-ENV:mustUnderstand="1">1</cwmp:ID>
</SOAP-ENV:Header>
<SOAP-ENV:Body><SOAP-ENV:Fault><faultcode>Server</faultcode>
<faultstring>CWMP fault</faultstring>
<detail><cwmp:Fault><FaultCode>9003</FaultCode>
<FaultString>Invalid arguments</FaultString>
<SetParameterValuesFault><ParameterName>InternetGatewayDevice.DeviceInfo.X_ZTE-COM_AdminAccount.</ParameterName>
<FaultCode>9002</FaultCode>
<FaultString>Internal error</FaultString>
</SetParameterValuesFault>
</cwmp:Fault>
</detail>
</SOAP-ENV:Fault>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

configuración de stunnel

El router conecta al puerto 9191 por https, lighttpd escucha en el puerto 80 por http, usamos stunnel para transformar la conexión de cifrada (https) a en claro (http).

Creamos el certificado

cd /etc/stunnel
openssl req -new -x509 -nodes -days 365 -out stunnel.pem -keyout stunnel.pem

Y seguimos las instrucciones.

Creamos el fichero /etc/stunnel/fakeacs.conf con este contenido

[acs]
accept = 9191
connect = 80
cert = /etc/stunnel/stunnel.pem

(re)arrancamos stunnel systemctl restart stunnel4

Podemos comprobar que funcione usando un navegador o curl contra https://localhost:9191

redirección

para que las peticiones vayan a nuestro servidor en lugar que al de digi:

iptables -t nat -A PREROUTING -p tcp --dest 188.26.208.7 -j REDIRECT --to-port 9191

Si solo dispones de una tarjeta de red y has seguido las instrucciones del primer paso para usar dnsmasq, esta redirección no hace falta.

OJO: no he comprobado si esta segunda opción funciona

forzar una conexión

La manera más sencilla de forzar una conexión es parar el servidor PPPoE y volverlo a arrancar. En el log de lighttp podremos ver si el router intenta conectar y/o podemos usar wireshark en el puerto 80 para ver la comunicación.

bonus track

Si queremos saber los parámetros que se pueden ajustar, usaremos este /etc/lighttpd/resp2

<SOAP-ENV:Envelope xmlns:SOAP="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:cwmp="urn:dslforum-org:cwmp-1-0" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<SOAP-ENV:Header>
<cwmp:ID SOAP:mustUnderstand="1">1</cwmp:ID>
<cwmp:NoMoreRequest>1</cwmp:NoMoreRequest>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<cwmp:GetParameterNames>
<cwmp:ParameterPath></cwmp:ParameterPath>
<cwmp:NextLevel>false</cwmp:NextLevel>
</cwmp:GetParameterNames>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

en req3 tendremos la lista de parámetros.

Si queremos leer uno o más parámetros (es solo un ejemplo)

<SOAP-ENV:Envelope xmlns:SOAP="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:cwmp="urn:dslforum-org:cwmp-1-0" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<SOAP-ENV:Header>
<cwmp:ID SOAP:mustUnderstand="1">1</cwmp:ID>
<cwmp:NoMoreRequest>1</cwmp:NoMoreRequest>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<cwmp:GetParameterValues>
<ParameterNames SOAP-ENC:arrayType="xsd:string[3]">
<string>InternetGatewayDevice.DeviceInfo.X_ZTE-COM_AdminAccount.Enable</string>
<string>InternetGatewayDevice.DeviceInfo.X_ZTE-COM_AdminAccount.Username</string>
<string>InternetGatewayDevice.DeviceInfo.X_ZTE-COM_AdminAccount.Password</string>
</ParameterNames>
</cwmp:GetParameterValues>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

Pero no os hagaís ilusiones: las password siempre salen vacías.

Continuar