×

松下的视频对讲机被黑以启用Alexa

消耗积分:0 | 格式:zip | 大小:0.16 MB | 2022-11-08

张鹏

分享资料个

描述

这种可视对讲在日本只有一个共用入口的典型公寓中很常见。大多数型号没有任何物联网功能,并且由于它们已集成到楼宇安全系统中,因此几乎不可能用智能门铃代替它们。因此,有些人使用 ADC、光传感器或音频传感器来检测呼叫并使用伺服电机来执行解锁按钮按下,从而入侵了他们公寓中的对讲机。但是,由于我喜欢人们无法仅从外面看就知道是否添加了 IoT 功能的 hack,所以这次我在家中破解了一个(松下的 SHVT18612WK),其方式是

  • 它的原始功能完好无损,从外部看不到破解。
  • 呼叫检测和解锁操作 100% 以电子方式执行。
  • 它安全地连接到 AWS 云。
  • 它播放预先录制的消息。

工作原理

我使用了带有Mongoose OS的ESP32微控制器,因为我相信这是物联网项目的最佳组合之一。我使用光电耦合器以电子方式检测呼叫并解锁入口门,并使用 DFPlayerMini播放预先录制的消息。

poYBAGNo8ZWAGVGWAABrlE-JwGo118.png
整体架构
 

以电子方式检测呼叫

当从入口发起视频通话时,可视对讲机上的钥匙形绿色 LED 开始闪烁。因此,通过将光耦合器的初级侧与该 LED 并联,将次级侧连接到 GPIO 和 GND,并检查 GPIO 的状态,您可以检测到呼叫。

当检测到呼叫时,ESP32 会向 AWS IoT Core 发布消息。然后自动执行 AWS Lambda 以发送 Slack 消息。

pYYBAGNo8ZeAIk6eAAEIliGHgSw926.png
检测来电并发送通知
 

以电子方式执行解锁按钮按下

通过将光耦的初级端连接到 GPIO 和 GND,次级端与对讲威廉希尔官方网站 板上的解锁按钮并联,并将 GPIO 从 L 设置为 H,然后再设置为 L,中间有轻微的延迟,您无需物理按下解锁按钮即可执行解锁操作。通话按钮也是如此。

AWS Amplify Web 应用程序和 Alexa 技能向 AWS IoT Core 发布消息,ESP32 接收消息并完成工作。

pYYBAGNo8ZqAHOWNAABYxaWUQxY588.png
解锁入口门
 

步骤 1. 暴露主 PCB 并寻找 hack 点

首先,拆下可视对讲机的侧盖并拧松螺丝。

poYBAGNo8cGADHOAAA7mxBQ1_jE199.jpg
卸下侧盖
 

在卸下电线束之前,请务必关闭电源开关。大多数型号都带有内置火灾警报器,当这些电线在电源开关打开的情况下被移除、切断或烧毁时,它就会关闭。

pYYBAGNo8ciAfqWhABBcqCuvOjg536.jpg
卸下主板
 

 

寻找容易被黑客入侵的地点。

pYYBAGNo8cqAFPajAAC3V7z8euI607.jpg
寻找黑客位置
 

将带状电缆焊接到黑客点。(电缆颜色)

  • 解锁待机 LED +(橙色)
  • 解锁待机 LED –(红色)
  • 解锁按钮(蓝色)
  • 通话按钮(绿色)
  • 解锁/通话按钮共用 GND(黄色)
poYBAGNo8cyAClocAADi9gxoXmQ774.jpg
将带状电缆焊接到主板
 

步骤 2. 构建威廉希尔官方网站

在迷你面包板上,放置 ESP32-DevKitC、光耦合器和 DFPayerMini。为尽可能避免稳定性问题,请使用实心跳线而不是柔性跳线。

我发现视频对讲面板上的钥匙形 LED 上的电压约为。3.0V,所以我使用 IF=7.5mA (and R=250ohm) 作为光耦进行呼叫检测,根据其数据表,这是在 VF=1.17V 下运行的推荐值如果这个IF太大,钥匙形LED不闪烁,如果太小,光耦将不起作用。我使用 IF=15mA(和 R=120ohm)作为光耦合器,用于通话和解锁按钮按下。

对于 DFPlayerMini,只连接 Rx,因为对于这个 hack,ESP32 不需要知道它何时完成播放音频文件,因此不需要 Tx。使用 Amazon Polly 生成 mp3 格式的音频消息并将其保存到 microSD。

pYYBAGNo8dCAUz0bAADds-0-EwU459.png
威廉希尔官方网站 的设计
 

实际威廉希尔官方网站 如下所示。你可以为此设计一个PCB。

poYBAGNo8dKAPSRuAACtHDibY8c388.jpg
 

步骤 3. 为 ESP32 编写代码并为 AWS IoT 预置它

对于这个项目,我使用了Mongoose OS ,一个非常强大的物联网固件开发框架,因此应用程序代码(init.js)可以用 JavaScript 编写。完整代码可在GitHub中找到

首先,将 Mongoose OS 安装到 ESP32 并使用以下命令将其连接到 Wi-Fi。

$ mos flash esp32
$ mos wifi SSID PASSWORD

通过加载 Mongoose OS API 开始编写 init.js,然后声明变量。

// Load Mongoose OS APIs
load('api_gpio.js');
load('api_mqtt.js');
load('api_sys.js');
load('api_timer.js');
load('api_uart.js');

// Declare variables
let ledPin = 12;
let talkBtn = 13;
let unlockBtn= 14;
let callState = false;
let uartNo =1;
let topic1 = 'intercom/detect';
let topic2 = 'intercom/unlock';
let qos = 1;

为 DFPlayerMini 设置 UART。

// UART Setup
UART.setConfig(uartNo, {
  baudRate: 9600,
  esp32: {
    gpio: {
      rx: 25,
      tx: 26,
    },
  },
});

设置 GPIO 模式并初始化 GPIO。

// Set GPIO mode
GPIO.setup_input(ledPin, GPIO.PULL_UP);  // iput & internally pulled up
GPIO.set_mode(startTalkingBtn, GPIO.MODE_OUTPUT);
GPIO.set_mode(openSecurityDoorBtn, GPIO.MODE_OUTPUT);

// Initialize GPIOs
GPIO.write(startTalkingBtn, 0);
GPIO.write(openSecurityDoorBtn, 0);

以下代码块检测调用并向 topic1 发布消息。Mongoose OS 带有一个有用的按钮处理程序,用于检测按钮按下。ledPin 是内部上拉的,所以它通常是 H 并在发起呼叫时变为 L。Timer.set() 使 callState 在 15 秒后恢复正常。

// Detect calls and publish a message to topic1
GPIO.set_button_handler(ledPin, GPIO.PULL_UP, GPIO.INT_EDGE_NEG, 20, function(x) {

  if (!callState) {

    callState = true;
    let message = JSON.stringify({ });
    let ok = MQTT.pub(topic1, message, qos);
    print(ok);
    print("-----Call detected, hopefully published to AWS IoT-----");

    Timer.set(15000, false, function() {
      callState = false;
      print("-----Back to normal-----");
    }, null);

  }

}, true);

要通过 Slack 发送通知,您可以使用发布到 topic1 和Incoming Hooks 的消息。创建一个将消息发送到 Slack 通道并配置 AWS IoT 规则以触发此 Lambda 的 Lambda 函数。

当从 AWS IoT Core 接收到消息时,以下代码块依次执行通话按钮按下、音频播放、解锁按钮按下和通话按钮按下。我在这里使用了 3 个定时器,因为在 Mongoose OS 中,对于这种用例,建议使用 Timer.set() 而不是 Sys.usleep() 来稳定运行。

// Subscribe to topic2 and unlock door when message is received
MQTT.sub(topic2, function(conn, msg) {

  print('-----Received message from AWS IoT-----')
  talk();

  Timer.set(2000, false, function() {
    play();
  }, null);

  Timer.set(4500, false, function() {
    unlock();
  }, null);

  Timer.set(9500, false, function() {
    talk();
  }, null);

}, true);

talk() 和 unlock() 所做的是将 GPIO 从 L 设置为 H,然后将 Sys.usleep() 设置回 L。这可以模拟实际的按钮按下。

// Mimic talk button press
function talk(){
  GPIO.write(talkBtn, 1);
  Sys.usleep(300000);
  GPIO.write(talkBtn, 0);
}

// Mimic unlock button press
function unlock(){
  GPIO.write(unlockBtn, 1);
  Sys.usleep(300000);
  GPIO.write(unlockBtn, 0);
}

DFPlayerMini 可以通过 UART 控制。参考在这里

// Play /01/001.mp3 with DFPlayerMini
function play(){
  UART.write(uartNo, '\x7E');
  UART.write(uartNo, '\xFF');
  UART.write(uartNo, '\x06');
  UART.write(uartNo, '\x0F');
  UART.write(uartNo, '\x00');
  UART.write(uartNo, '\x01');
  UART.write(uartNo, '\x01');
  UART.write(uartNo, '\xEF');
}

由于 Mongoose OS 包含适用于嵌入式 C 的 AWS IoT 设备开发工具包并执行将 ESP32 连接到 AWS IoT Core 所需的一切操作,因此您需要执行以下命令。确保您准备好您的访问密钥 ID 和秘密访问密钥对,并事先在您的计算机上进行设置。

$ mos aws-iot-setup --aws-region AWS_REGION

对于 Alexa 技能,创建一个具有向主题 2 发布消息的欢迎意图,对讲/解锁。如果你使用 python,这样的东西会起作用。

client = boto3.client('iot-data', region_name='es-east-1')
response = client.publish(
    topic='intercom/unlock',
    qos=1,
    payload=json.dumps({ })
)

网上有很多如何创建 Alexa Skill 和 Amplify web 应用程序,所以请参考那些创建自己的 Skill 和应用程序的方法。

第 4 步:做电气工作,把所有东西都藏在墙上

从墙上拆下可视对讲机的底座。

poYBAGNo8diAWp-8AA6atoKkEvo842.jpg
基本单元
 

拆下交流电源线,并在交流电源线上做一个分支。将带有 USB 充电端口的壁式插座连接到分支,并将交流电源线连接到基本单元。

pYYBAGNo8d6AQNv7AA4OSe3-j00302.jpg
连接墙上插座
 

 

使用微型 USB 电缆为 ESP32 供电并将所有东西隐藏在墙上。确保将扬声器放置在靠近麦克风的位置,否则客人无法听到音频消息。

poYBAGNo8eWATGqrAA6m1flUpro895.jpg
在隐藏一切之前
 

现在破解完成了!

pYYBAGNo8eyAaaBLAAps62e5Fn4088.jpg
从外面看不到黑客!
 

未来发展方向

我想为这个项目制作一个PCB。我还想分析视频信号,将其从板上取出,然后发送到 AWS 云来做一些有趣的事情。


声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

评论(1)
发评论
jf_18382495 2023-04-14
0 回复 举报
感谢分享 收起回复

下载排行榜

全部1条评论

快来发表一下你的评论吧 !

'+ '

'+ '

'+ ''+ '
'+ ''+ ''+ '
'+ ''+ '' ); $.get('/article/vipdownload/aid/'+webid,function(data){ if(data.code ==5){ $(pop_this).attr('href',"/login/index.html"); return false } if(data.code == 2){ //跳转到VIP升级页面 window.location.href="//m.obk20.com/vip/index?aid=" + webid return false } //是会员 if (data.code > 0) { $('body').append(htmlSetNormalDownload); var getWidth=$("#poplayer").width(); $("#poplayer").css("margin-left","-"+getWidth/2+"px"); $('#tips').html(data.msg) $('.download_confirm').click(function(){ $('#dialog').remove(); }) } else { var down_url = $('#vipdownload').attr('data-url'); isBindAnalysisForm(pop_this, down_url, 1) } }); }); //是否开通VIP $.get('/article/vipdownload/aid/'+webid,function(data){ if(data.code == 2 || data.code ==5){ //跳转到VIP升级页面 $('#vipdownload>span').text("开通VIP 免费下载") return false }else{ // 待续费 if(data.code == 3) { vipExpiredInfo.ifVipExpired = true vipExpiredInfo.vipExpiredDate = data.data.endoftime } $('#vipdownload .icon-vip-tips').remove() $('#vipdownload>span').text("VIP免积分下载") } }); }).on("click",".download_cancel",function(){ $('#dialog').remove(); }) var setWeixinShare={};//定义默认的微信分享信息,页面如果要自定义分享,直接更改此变量即可 if(window.navigator.userAgent.toLowerCase().match(/MicroMessenger/i) == 'micromessenger'){ var d={ title:'松下的视频对讲机被黑以启用Alexa',//标题 desc:$('[name=description]').attr("content"), //描述 imgUrl:'https://'+location.host+'/static/images/ele-logo.png',// 分享图标,默认是logo link:'',//链接 type:'',// 分享类型,music、video或link,不填默认为link dataUrl:'',//如果type是music或video,则要提供数据链接,默认为空 success:'', // 用户确认分享后执行的回调函数 cancel:''// 用户取消分享后执行的回调函数 } setWeixinShare=$.extend(d,setWeixinShare); $.ajax({ url:"//www.obk20.com/app/wechat/index.php?s=Home/ShareConfig/index", data:"share_url="+encodeURIComponent(location.href)+"&format=jsonp&domain=m", type:'get', dataType:'jsonp', success:function(res){ if(res.status!="successed"){ return false; } $.getScript('https://res.wx.qq.com/open/js/jweixin-1.0.0.js',function(result,status){ if(status!="success"){ return false; } var getWxCfg=res.data; wx.config({ //debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。 appId:getWxCfg.appId, // 必填,公众号的唯一标识 timestamp:getWxCfg.timestamp, // 必填,生成签名的时间戳 nonceStr:getWxCfg.nonceStr, // 必填,生成签名的随机串 signature:getWxCfg.signature,// 必填,签名,见附录1 jsApiList:['onMenuShareTimeline','onMenuShareAppMessage','onMenuShareQQ','onMenuShareWeibo','onMenuShareQZone'] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2 }); wx.ready(function(){ //获取“分享到朋友圈”按钮点击状态及自定义分享内容接口 wx.onMenuShareTimeline({ title: setWeixinShare.title, // 分享标题 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); //获取“分享给朋友”按钮点击状态及自定义分享内容接口 wx.onMenuShareAppMessage({ title: setWeixinShare.title, // 分享标题 desc: setWeixinShare.desc, // 分享描述 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 type: setWeixinShare.type, // 分享类型,music、video或link,不填默认为link dataUrl: setWeixinShare.dataUrl, // 如果type是music或video,则要提供数据链接,默认为空 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); //获取“分享到QQ”按钮点击状态及自定义分享内容接口 wx.onMenuShareQQ({ title: setWeixinShare.title, // 分享标题 desc: setWeixinShare.desc, // 分享描述 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); //获取“分享到腾讯微博”按钮点击状态及自定义分享内容接口 wx.onMenuShareWeibo({ title: setWeixinShare.title, // 分享标题 desc: setWeixinShare.desc, // 分享描述 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); //获取“分享到QQ空间”按钮点击状态及自定义分享内容接口 wx.onMenuShareQZone({ title: setWeixinShare.title, // 分享标题 desc: setWeixinShare.desc, // 分享描述 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); }); }); } }); } function openX_ad(posterid, htmlid, width, height) { if ($(htmlid).length > 0) { var randomnumber = Math.random(); var now_url = encodeURIComponent(window.location.href); var ga = document.createElement('iframe'); ga.src = 'https://www1.elecfans.com/www/delivery/myafr.php?target=_blank&cb=' + randomnumber + '&zoneid=' + posterid+'&prefer='+now_url; ga.width = width; ga.height = height; ga.frameBorder = 0; ga.scrolling = 'no'; var s = $(htmlid).append(ga); } } openX_ad(828, '#berry-300', 300, 250);