|Hacker实例:自动按YubiKeys


黑客精神的第一法则是遇到问题自己解决 , 不管硬件还是软件都要自己动手DIY来解决问题 。 很多人可能对这个可能有些好奇 , 实际上这也是一个平常探索的过程 。 今天我们就通过一个实例来学习该过程——打造一个自动按YubiKeys机 。
缘起
从事技术工作的小伙伴们可能很多人都知道YubiKey , 比如下面的这个YubiKey 5C Nano 。

|Hacker实例:自动按YubiKeys
本文插图
YubiKeys主要用来充当两因素身份验证 。 在以前的文章中 , 虫虫曾经介绍过用YubiKeys来认证以及SSH登陆的文章 。 这Web双因子认证过程中使用用户名和密码登录到系统后 , 系统还需要以额外的第二种方式进行授权 。 这样 , 如果账号密码泄露 , 攻击者也将无法得到第二种身份验证形式 , 这样防止账号被盗保障安全 。 两因子验证有多种形式一种常见的形式是网站会要求使用手机上的谷歌Authenticator应用程序(或类似程序 , 比如FreeOTP)扫描QR码 , 该代码会生成6位数字的验证码 。 服务器和应用程序都有一个共享的机密 。 手机会根据密钥和当前时间戳生成代码 , 服务器会生成相同的代码并验证两者是否匹配 。

|Hacker实例:自动按YubiKeys
本文插图
还有基于短信的的双因子认证:服务器会生成一个代码 , 并通过短信将其发送到的手机 。 由于存在SIM劫持的攻击 , 诱骗手机运营商将号码移植到新的SIM卡上 , 从而可以所有SMS流量引向他们的手 。 所以被认为是不太安全的双因子认证方式 。
YubiKeys是插入计算机USB端口并模拟键盘的小型设备 。 轻按后 , 它们会发出一次性密码(OTP) , 然后可以由验证服务器进行验证 。 YubiKeys上保存着用于签名信息的私钥 , 而且该私钥无法被复制和窃取 , 所以保证了安全 。
本案例中 , Bertrand使用的YubiKey始终插在笔记本电脑上 , 所以 , 不论将笔记本电脑从办公桌上带到会议室或其他办公室 , 保证就始终可用 。 但是他的笔记本不打算移动使用 , 并且还外部显示器并节省了一些桌面空间 , 笔记本翻盖垂直放置在架子上 。 这样一来 , 按下YubiKey会非常麻烦而且触发率不高 。
由于YubiKey 5C Nano的触发目标区域非常小 , 如下面的黄色线部分 。

|Hacker实例:自动按YubiKeys
本文插图
YubiKey的功能之一是 , 黄色小金属条防止由于将笔记本电脑撞到某物而意外触发它 , 尝试触发它的5次中有1次 。 确保不能从计算机本身的软件触发YubiKey的想法已经很多 。
如果远程攻击者要破坏的笔记本电脑 , 则可以从计算机上的软件触发YubiKey , 这将使无法使用YubiKey 。 但是在安全性和便利性之间进行权衡:例如 , 通常不必在每次访问系统时都输入YubiKey , 某些系统只会询问一次 , 而在以后的某个登录中不再询问多少时间 。
Bertrand本次Hack的目标是是如何使用软件自动触发YubiKey——Finger 。
硬件设计
首先 , 需要某种方式让计算机与The Finger对话 。 有一堆这些IZOKEE D1 Mini开发板 , 它们是使用许多IoT设备中ESP8266芯片的较小版本的板 。

|Hacker实例:自动按YubiKeys
本文插图
可以将其连接到笔记本电脑并通过USB串行与之对话 , 但是由于它具有WiFi , 也可以在其上运行网络服务器并发送HTTP请求 。
接下来 , 需要一些方法将Finger推向Yubikey 。 Bertrand谷歌后 , 发现了28BYJ-48步进电机可以与D1 Mini板配合使用 。

|Hacker实例:自动按YubiKeys分页标题
本文插图
【|Hacker实例:自动按YubiKeys】
步进电机将电脉冲转换为机械旋转 , 而D1 Mini具有用于发送电脉冲的引脚 。

|Hacker实例:自动按YubiKeys
本文插图
但是步进电机会旋转 , 通常只需要沿直线方向戳一下即可 。 因此搜索了''28BYJ-48'' , 发现了这一点:28BYJ-48 Motor Halter 。

|Hacker实例:自动按YubiKeys
本文插图
这将齿轮连接到电动机 , 该齿轮可以前后引导长齿条 。 要向YubiKey推一个长的塑料东西 , 它看起来就像一根手指 。 在Fusion 360中打开了这两个模型 , 并使用了一种称为'' smooshing''的高级CAD技术 , 结果就是:

|Hacker实例:自动按YubiKeys
本文插图
接下来 , 导出了污损的STL , 并在Prusament PLA Lipstick Red将其用3D打印出来了 。 然后 , 用塑料手指触摸了YubiKey , 结果没有按照预期成功触发工作 。 但是用桌上的金属螺丝测试 , 可以成功触发YubiKey , 立即发出OTP 。
知道原因后Bertrand对该塑料Fingle进行了改造:用虎钳将其固定在办公桌上 , 并在其中钻了一个小孔 , 然后将金属螺钉拧入其中 , 然后将其与YubiKey碰触 , 结果还是不行!

|Hacker实例:自动按YubiKeys
本文插图
后来他发现将金属螺钉触摸到Yubikey时 , 它只是将电荷从身体传输到金属螺钉 , 然后将其传输到YubiKey上的电容式触摸传感器 。 那么 , 如何欺骗电容式触摸传感器以为它是真正的手指呢?
据猜想电容式触摸传感器的工作方式是它们通过测量人体对地面的电容 , 因此 , 如果直接将传感器连接到地面 , 它会认为其真正导电或至少对人体足够导电手指要介于两者之间 。 因此 , 拿了一根绝缘电线 , 稍微拧开金属螺钉 , 将其缠绕在螺钉上 , 然后再次拧紧 。 然后 , 将另一端连接到D1 Mini板上的GND端口 , 将其触摸到YubiKey , 然后它起作用了!
现在 , 步进电机的驱动器板已经连接到D1 Mini上的5V和GND , 所以可能需要剥开GND线 , 然后将其同时连接到驱动器板和螺钉上 。 后来将金属丝的一端从步进电机的金属本体(假设金属本体的外壳已接地)和塑料外壳之间的金属螺钉上楔入即可 。

|Hacker实例:自动按YubiKeys
本文插图
一旦确认手指会触发YubiKey , 就需要一种将YubiKey安装在手指附近的方法 , 因此使用了数字卡尺来测量USB-C扩展电缆的尺寸 , 并在Fusion 360中设计了一个支架 。

|Hacker实例:自动按YubiKeys
本文插图
USB-C扩展电缆将插入左侧的孔中 , 而电动机将安装在右侧 。
此时 , 必须将步进电机驱动器板连接到D1 Mini 。 这可以通过将一些接头焊接到D1 Mini上 , 然后在它们之间连接一些跨接线来完成 。

|Hacker实例:自动按YubiKeys
本文插图

|Hacker实例:自动按YubiKeys
本文插图
将步进电机放入外壳并将所有零件拧在一起后:

|Hacker实例:自动按YubiKeys
本文插图
软件设计
该系统软件部分更加简单 。 可以使用Arduino IDE对D1 Mini进行编程 。 首先 , 进入''首选项'' , 然后package_esp8266com_index.json 添加 。 然后 , 当您进入板管理器时 , 可以安装esp8266包括LOLIN(WEMOS)D1 R2&mini板在内的软件包 , 应在''工具''下选择该软件包 。分页标题
先运行一个示例来使LED闪烁 , 以验证其是否正常工作:
void setup() { pinMode(LED, OUTPUT); } void loop() { digitalWrite(LED, LOW); delay(1000); digitalWrite(LED, HIGH); delay(1000); }然后是使用WiFi控制28BYJ-48步进电机的示例程序:
int Pin1 = D1; //IN1 is connected int Pin2 = D2; //IN2 is connected int Pin3 = D3; //IN3 is connected int Pin4 = D4; //IN4 is connected int pole1[] ={0,0,0,0, 0,1,1,1, 0}; //pole1, 8 step values int pole2[] ={0,0,0,1, 1,1,0,0, 0}; //pole2, 8 step values int pole3[] ={0,1,1,1, 0,0,0,0, 0}; //pole3, 8 step values int pole4[] ={1,1,0,0, 0,0,0,1, 0}; //pole4, 8 step values int poleStep = 0; int dirStatus = 3; String argId[] ={''ccw'', ''cw''}; ... void loop(void) { server.handleClient(); MDNS.update(); if (dirStatus == 1) { poleStep++; driveStepper(poleStep); } else if (dirStatus == 2) { poleStep--; driveStepper(poleStep); } else { driveStepper(8); } if (poleStep>7) { poleStep=0; } if (poleStep<0) { poleStep=7; } delay(1); } void motorControl() { if (server.arg(argId[0]) == ''on'') { dirStatus = 1; // CCW } else if (server.arg(argId[0]) == ''off'') { dirStatus = 3; // motor OFF } else if (server.arg(argId[1]) == ''on'') { dirStatus = 2; // CW } else if (server.arg(argId[1]) == ''off'') { dirStatus = 3; // motor OFF } } void driveStepper(int c) { digitalWrite(Pin1, pole1[c]); digitalWrite(Pin2, pole2[c]); digitalWrite(Pin3, pole3[c]); digitalWrite(Pin4, pole4[c]); }它的工作方式是Web服务器显示两个按钮:CCW(逆时针)和CW(顺时针) 。 如果这两个按钮中的任何一个都被切换 , 它将更改dirStatus为1(对于CCW)和2(对于CW) 。 如果该按钮处于关闭状态 , 它将变为dirStatus3以停止电动机 。
您可以在loop()函数中看到正在检查它是dirStatus增加poleStep(直到它循环) , 减小(直到它循环)或完全停止 。
相反 , 想要的是一个HTTP接口 , 它将使电动机逆时针移动 , 直到碰到Yubikey , 然后顺时针旋转以收回 , 然后停止 。
因此 , 可以将motorControl()函数重写为:
void motorControl() { dirStatus = 1; // CCW }当调用HTTP接口时 , 它将开始逆时针移动电动机 。
然后 , 我们修改loop()函数以移动400步 , 将方向更改为CW , 然后沿该方向移动400步 , 然后停止 。
int steps = 0; void loop(void) { server.handleClient(); MDNS.update(); if (dirStatus == 1) { poleStep++; driveStepper(poleStep); steps++; } else if (dirStatus == 2) { poleStep--; driveStepper(poleStep); steps++; } else { driveStepper(8); } if (poleStep>7) { poleStep=0; } if (poleStep<0) { poleStep=7; } if (steps > 400) { if (dirStatus == 1) { dirStatus = 2; // CW } else { dirStatus = 3; // motor OFF } steps = 0; } delay(1); }关于Finger的物理设计的一件好事是 , 它非常宽容:电机不是很坚固 , 因此一旦碰到YubiKey , 它就可以继续逆时针方向转动而不会损坏任何东西 。 当顺时针旋转时 , 最终从手指伸出的骨头会撞到底座的边缘 , 从而防止其掉落到右侧 。 从steps最大极限开始 , 然后进行了手动测试 , 每次降低一点 , 直到找到400个台阶的最佳点 。
然后 , 我检查了WiFi板的MAC地址 , 在路由器上为其进行了静态IP映射 , 并对其进行了本地DNS记录finger.localdomain 。
现在 , 如果调用finger.localdomain/press , 电动机将把手指推向YubiKey并缩回 。分页标题
触发脚本
如果用手指按一下YubiKey不太令人满意 , 则在机械键盘的另一端按一个键 。 如果只要敲击键盘上的一个键就可以触发YubiKey , 那就太酷了 。
如果使用TKL布局 , 则在键盘的右上角具有''打印屏幕'' , ''滚动锁定''和''暂停'' , 所有这些在2020年都没有多大意义 , 并且可以重新映射 。
实例中使用一个名为Karabiner-Elements的程序来帮助进行这种重新映射 。 就像该项目的硬件部分一样 , 它也具有Rube Goldberg风格 。
使用用户界面 , 在''简单修改''选项卡下 , 可以将''从键''更改为''暂停'' , 将''至键''更改为'' f14'' 。
然后切换到''其他''选项卡 , 然后单击''打开配置文件夹(?/.config/ karabiner)'' 。 在这里找到一个名为的文件karabiner.json 。
在profiles.rules键下 , 可以添加以下JSON:
{ ''description'': ''F14 to trigger Yubikey'', ''manipulators'': [ { ''from'': { ''key_code'': ''f14'', ''modifiers'': { ''optional'': [''any''] } }, ''to'': [ { ''shell_command'': ''osascript /Users/YOUR_USERNAME/bin/yubikey.scpt'' } ], ''type'': ''basic'' } ] },在其中 , ~/bin/yubikey.scpt可以编写一个Applescript来调用shell脚本 , 如下所示:
do shell script ''/bin/sh ~/bin/yubikey.sh 2>&1 &''为什么Applescript会调用Shell脚本?当直接从Karabiner Elements启动shell脚本时 , 它打开的新实例 , Terminal.app并将焦点从提示输入YubiKey的窗口移开 。 这将使所有内容在后台运行 。
最后 , 在~/bin/yubikey.sh有:
#!/bin/bash curl '' finger.localdomain/press'' --silent >> /dev/null通过制作了一个YubiKey提示进行演示 , 它也可以在真实的YubiKey提示中使用 。 这是伪造的YubiKey提示符的代码 , 以防万一由于某些程序需要制作伪造的YubiKey提示符:
#!/bin/bash printf ''YubiKey for 'bert': '' read yubikey green=`tput setaf 2` reset=`tput sgr0` echo ''${green}SUCCESS${reset}''有了该shell脚本 , 也就可以从其他地方调用它 。 iTerm2具有称为Triggers的功能 , 该功能可以根据与终端中的正则表达式匹配的文本执行操作 。 因此 , 可以编写一个正则表达式来监听'' Yubikey for'' , 并使其运行相同的脚本 , 而无需完全按下按钮 。
另一个选择是制作一个自定义的Chrome扩展程序 , 该扩展程序等待某些请求YubiKeys的URL , 并使浏览器在后台获取到我们的HTTP端点 。
总结
该实例中通过软硬件实例 , 制作了一个自动''按''YubiKeys的的工程 , 也许对其他人来说这是没有什么蛋用的东西 。 但是这个解决问题的思路和实例动手能力则正是Hacker精神所在 , 这也是我们需要学习的东西 。 介绍该完整实例过程希望对大家都有所启发帮助 。