-
Notifications
You must be signed in to change notification settings - Fork 8
simula tr069.md
La comunicación siempre es activada desde el router:
- El router conecta con el servidor
- El servidor envía comandos al router en la respuesta (o nada si no hay más comandos para ejecutar)
- 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.
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>
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
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
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.
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.