V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
est
V2EX  ›  PHP

PHP 探测任意网站密码明文/加密手段办法: md5('240610708') == md5('QNKCDZO')

  •  5
     
  •   est · 2015-05-04 15:51:31 +08:00 · 27009 次点击
    这是一个创建于 3520 天前的主题,其中的信息可能已经有所发展或是发生改变。
    var_dump(md5('240610708') == md5('QNKCDZO'));
    var_dump(md5('aabg7XSs') == md5('aabC9RqS'));
    var_dump(sha1('aaroZmOk') == sha1('aaK1STfY'));
    var_dump(sha1('aaO8zKZF') == sha1('aa3OFF9m'));
    var_dump('0010e2' == '1e3');
    var_dump('0x1234Ab' == '1193131');
    var_dump('0xABCdef' == ' 0xABCdef');

    感觉这个不科学啊

    https://news.ycombinator.com/item?id=9484757
    79 条回复    2015-12-08 15:16:31 +08:00
    ywisax
        1
    ywisax  
       2015-05-04 15:59:28 +08:00   ❤️ 2
    观察下最终的hash就明白了,都是0eXXXXXXXX 。
    再加上php是弱语言,会自动判断数据类型。
    零=零,明白了吧?
    anyforever
        2
    anyforever  
       2015-05-04 16:01:40 +08:00
    md5('240610708'); // 0e462097431906509019562988736854
    md5('QNKCDZO'); // 0e830400451993494058024219903391

    怎么可能这么容易碰撞
    anyforever
        3
    anyforever  
       2015-05-04 16:03:25 +08:00
    var_dump(md5('240610708') === md5('QNKCDZO'));
    ywisax
        4
    ywisax  
       2015-05-04 16:04:00 +08:00   ❤️ 2
    准确点说,是“==”对比的时候会进行数据转换,0eXXXXXXXXXX 转成0了。
    了解php的“==”和“===“就更加清晰了。
    yangff
        5
    yangff  
       2015-05-04 16:08:28 +08:00   ❤️ 3
    aliang032
        6
    aliang032  
       2015-05-04 16:12:56 +08:00   ❤️ 1
    找了下手册说明贴给大家:

    如果比较一个数字和字符串或者比较涉及到数字内容的字符串,则字符串会被转换为数值并且比较按照数值来进行

    http://php.net/manual/zh/language.operators.comparison.php
    est
        7
    est  
    OP
       2015-05-04 16:21:17 +08:00
    @ywisax
    @yangff

    脑洞够大!
    xifangczy
        8
    xifangczy  
       2015-05-04 16:34:44 +08:00
    卧槽 这脑洞。。太赞了
    raincious
        9
    raincious  
       2015-05-04 16:36:13 +08:00
    这是个坑没错,所以密码比较的时候需要用 ===。但,怎么用它来:

    > PHP 探测任意网站密码明文/加密手段办法

    ?不解。
    est
        10
    est  
    OP
       2015-05-04 16:47:41 +08:00   ❤️ 16
    @raincious 把你的密码设成 0x1234Ab,然后退出登录再登录,换密码 1193131 登录,如果登录成功,那么密码绝对是明文保存的没跑。


    同理,密码设置为 240610708,换密码 QNKCDZO 登录能成功,那么密码没加盐直接md5保存的。
    cat9life
        11
    cat9life  
       2015-05-04 17:00:31 +08:00
    长见识啊...
    avtester
        12
    avtester  
       2015-05-04 17:03:44 +08:00
    知道了又能如何?
    bingu
        13
    bingu  
       2015-05-04 17:04:55 +08:00
    呃,这个略迪奥
    xierch
        14
    xierch  
       2015-05-04 17:06:20 +08:00
    PHP 的大坑哈哈哈
    tabris17
        15
    tabris17  
       2015-05-04 17:07:41 +08:00
    能强等的地方我都用强等的
    NeoAtlantis
        16
    NeoAtlantis  
       2015-05-04 17:09:45 +08:00 via Android   ❤️ 1
    散列不叫加密!
    要不谁给我解密看看?XD
    wy315700
        17
    wy315700  
       2015-05-04 17:12:46 +08:00
    收藏了 ,好牛逼的攻击
    raincious
        18
    raincious  
       2015-05-04 18:22:46 +08:00
    @est

    恍然大悟,感谢!
    Citrus
        19
    Citrus  
       2015-05-04 18:31:35 +08:00 via iPhone
    第一次见到如此能唬人的标题党。。。看标题以为楼主完全攻破了 MD5 可以批量找碰撞了。。。
    rwalle
        20
    rwalle  
       2015-05-04 18:46:33 +08:00
    PHP中的==是挺坑的
    但是PHP中还有很多同样大的坑。。。
    codejay
        21
    codejay  
       2015-05-04 18:47:30 +08:00
    这不是两个字符串比较吗 为什么要转换成数字
    wy315700
        22
    wy315700  
       2015-05-04 18:51:51 +08:00
    @codejay php会转义一部分字符串到数字的。。。
    gDD
        23
    gDD  
       2015-05-04 18:54:27 +08:00 via iPhone
    @est @raincious 不一定,我所有判断都用 === 或者 !== 判断,只有不专业选手用 == 判断才会出你说的脑洞…
    gDD
        24
    gDD  
       2015-05-04 18:55:57 +08:00 via iPhone
    还有判断密码,secret 等要用 hash_equals(),直接用 === 会出 Timing Attack 漏洞的。
    lincanbin
        25
    lincanbin  
       2015-05-04 19:05:45 +08:00
    @gDD hash_equals版本要求太高了,只能自己项目用着玩,开源项目用不了。
    gDD
        26
    gDD  
       2015-05-04 19:13:34 +08:00 via iPhone
    @lincanbin 开源项目我觉得反而更容易解决,composer 一个 symfony security core 就好,里面有 hash_equals 的 shim,反而是公司内没用 composer 管理的的私有项目比较难维护。
    noanti
        27
    noanti  
       2015-05-04 19:50:33 +08:00
    这是php的feature?
    php还真是最好的语言。。。
    tSQghkfhTtQt9mtd
        28
    tSQghkfhTtQt9mtd  
       2015-05-04 19:56:19 +08:00 via Android
    password_hash() 路过......
    belin520
        29
    belin520  
       2015-05-04 20:07:33 +08:00 via Android
    md5,加盐,md5,取前30位
    xiaozi
        30
    xiaozi  
       2015-05-04 20:09:45 +08:00
    这完全是没有 ===,如果是 ===, 根本就没办法检测吧。
    lyf362345
        31
    lyf362345  
       2015-05-04 20:25:34 +08:00
    @yangff 好大
    lyf362345
        32
    lyf362345  
       2015-05-04 20:32:43 +08:00
    @est 这个有意思
    est
        33
    est  
    OP
       2015-05-04 20:46:50 +08:00
    @gDD wordpress专业不?
    invite
        34
    invite  
       2015-05-04 22:02:18 +08:00
    从另一方面印证了:PHP 是全宇宙最牛逼的语言。
    barbery
        35
    barbery  
       2015-05-04 22:11:55 +08:00
    官方都建议直接用password_hash加密,用md5还不加salt,我就真的没话说了
    Jaylee
        36
    Jaylee  
       2015-05-04 22:16:21 +08:00
    搞不懂这个贴子为啥到处都是,做PHP的人基础都这么差? 都没看过手册?
    est
        37
    est  
    OP
       2015-05-04 22:56:45 +08:00
    @Jaylee 这个bug是最近wordpress爆出来的。。你是想说wordpress的人基础差么。。。
    Kabie
        38
    Kabie  
       2015-05-04 23:04:14 +08:00
    @est 基础好的人用PHP吗。。。
    kofj
        40
    kofj  
       2015-05-04 23:48:54 +08:00
    楼主的语法有问题.fix:探测任意php网站密码明文/加密手段办法
    Jaylee
        41
    Jaylee  
       2015-05-04 23:57:03 +08:00
    @est 不管是不是wordpress基础差,至少我能看出是PHP弱类型导致的。再说,这也不过是一个小bug而已,有必要往这里发?
    bdnet
        42
    bdnet  
       2015-05-04 23:58:56 +08:00
    除了用 === ,还可以用 strcmp ,返回 0 是相等
    bdnet
        43
    bdnet  
       2015-05-05 00:02:34 +08:00
    PHP是世界上最好的语言

    2333
    iyaozhen
        44
    iyaozhen  
       2015-05-05 01:22:19 +08:00   ❤️ 1
    @est 不是一般都数据库查询比较吗?SELECT count(*) FROM user WHERE username = '$username' AND password = '$password';
    czb
        45
    czb  
       2015-05-05 04:42:23 +08:00 via Android
    evlos
        46
    evlos  
       2015-05-05 05:40:38 +08:00
    看到 #44 我好像突然知道为什么很多网站连密码都有格式限制了。。。
    rwalle
        47
    rwalle  
       2015-05-05 06:02:30 +08:00
    44楼。。。
    djyde
        48
    djyde  
       2015-05-05 08:04:17 +08:00
    作为一个 JavaScripter,我表示用 === 是个良好的习惯
    lincanbin
        49
    lincanbin  
       2015-05-05 08:13:01 +08:00 via Android
    @iyaozhen 你这样写要注入了……
    kfll
        50
    kfll  
       2015-05-05 08:53:21 +08:00 via iPhone
    @iyaozhen 如果要告诉用户用户名不存在还是密码错误的话,
    hahastudio
        51
    hahastudio  
       2015-05-05 10:04:25 +08:00
    太可怕
    HN 的这条回复很能说明问题:
    They're comparing two things of the same type: two strings!
    chaucerling
        52
    chaucerling  
       2015-05-05 10:10:43 +08:00
    语言设计上的坑太多233
    fashioncj
        53
    fashioncj  
       2015-05-05 10:35:08 +08:00
    作为一个渗透学习者最喜欢44楼这样的程序猿了~
    66beta
        54
    66beta  
       2015-05-05 10:57:28 +08:00
    44楼处世未深,你们别欺负他
    tuoxie007
        55
    tuoxie007  
       2015-05-05 11:04:38 +08:00
    PHP是世界上最好的语言 +1
    yxzblue
        56
    yxzblue  
       2015-05-05 11:05:56 +08:00
    看来dz生成一个随机的salt值进行二次加密再保存,果然是要好一些啊。
    gDD
        57
    gDD  
       2015-05-05 11:22:23 +08:00
    @est 一开始我以为 (string) == (string) 是绝对以字符串形式做对比的,但是查了 PHP Manual 之后,发现If you compare a number with a string **or the comparison involves numerical strings, then each string is converted to a number and the comparison performed numerically**. 确实也业余了一把,简直宇宙最大坑!xD -- http://php.net/manual/en/language.operators.comparison.php

    说几个相关项目:

    Laravel 4 的时候也爆出过一个更直接的漏洞,直接传入 'true' 就足够。 -- http://barryvdh.nl/laravel/2015/02/21/csrf-protection-in-laravel-explained/

    jQuery 的规范里规定了 Strict equality checks (===) must be used in favor of abstract equality checks (==). The only exception is when checking for undefined and null by way of null. -- https://contribute.jquery.org/style-guide/js/

    而 PHP 的 == 比 JavaScript 的 == 更散漫,本身 PHP 里 null 和 false 就是要用 === 来判断的,这回 OP 的问题一受到重视,连 (string) 也必须强制 === 了。
    zhengkai
        58
    zhengkai  
       2015-05-05 12:06:51 +08:00   ❤️ 2
    上午研究了一下这个问题,根本原因是科学计数法这个 feature

    php > var_dump('0e1' == '0e2');
    bool(true)

    “数字 e 数字”格式的字符串有时被作为数字,有时被作为字符串



    php > echo intval('1e10');
    1
    php > echo '1e10' + 0;
    10000000000

    但是混蛋就混蛋在 (string) == (string) 时也会做这个转换,这就没法搞了(更何况都是字符串还要这么转换,也会降低性能)

    比方说 switch((string)$s) { 的时候就完全没法规避这个问题

    前同事从源码里看到这个判断的函数叫 zendi_smart_strcmp

    下一个补丁应该能修正这个问题(纯字符串比较不做转换),但是这个问题感觉还是挺伤的
    bravecarrot
        59
    bravecarrot  
       2015-05-05 12:45:48 +08:00 via iPad
    @est 脑洞大,蛮有道理
    iyaozhen
        60
    iyaozhen  
       2015-05-05 13:26:13 +08:00
    @evlos
    @rwalle
    @lincanbin
    @66beta
    @fashioncj
    汗。。。求说清楚呀,我感觉我老板要开除我了。
    肯定不直接拼sql,我也知道一点 sql 注入,但是一直浮于表面,求指点。
    $password 拼 sql 之前肯定会 $password = sha1/md5($password+$salt) 。
    账号($username)的话一般有限制只能数字或者字母,然后自我安慰 mysql_real_escape_string() 一下(老感觉这个不靠谱)。
    当然这样就只能提示账号或密码错误(不匹配)。

    要看账号是不是存在,SELECT count(*) FROM user WHERE username = '$username'; 这样?看来账号也不能明文存。是不是可以可逆加密或者简单的 base64 编码一下。
    Daniel65536
        61
    Daniel65536  
       2015-05-05 13:33:00 +08:00 via iPad
    @iyaozhen username= " ' or 1=1 or ' "
    iyaozhen
        62
    iyaozhen  
       2015-05-05 13:41:50 +08:00
    @Daniel65536 这个我知道,一般账号也只允许字母或数字。而且分号会被mysql_real_escape_string过滤掉吧。

    我的本意是若网站使用 SELECT count(*) FROM user WHERE username = '$username' AND password = '$password'; 这种方式的话“把你的密码设成 0x1234Ab,然后退出登录再登录,换密码 1193131 登录,如果登录成功,那么密码绝对是明文保存的没跑。”就不能说明网站是明文保存呀。
    lincanbin
        63
    lincanbin  
       2015-05-05 13:42:33 +08:00
    http://www.94cb.com/t/2516

    昨晚睡觉前写了一篇来解释PHP中隐式转换的这个问题。
    lincanbin
        64
    lincanbin  
       2015-05-05 13:46:36 +08:00
    @iyaozhen 引号过滤然后直接拼接SQL语句是个不推荐的做法了,现在PHP官方建议使用PDO类或者mysqli类来替代mysql系列函数。
    也就是参数绑定,这样做的话,SQL命令与参数会分两次传到MySQL的socket,MySQL根据接收顺序就可以识别出命令和参数,从而避免在参数中构造命令(也就是SQL注入)。
    PDO的话可以参考这个
    https://github.com/lincanbin/PHP-PDO-MySQL-Class
    est
        65
    est  
    OP
       2015-05-05 13:55:43 +08:00
    @iyaozhen 逻辑老师呢?

    “只要改成A密码用B密码也能登录,说明是该php网站一定是明文保存密码的。”

    反过来一定成立吗?
    iyaozhen
        66
    iyaozhen  
       2015-05-05 14:00:08 +08:00
    @lincanbin 嗯,谢谢。这个我了解过。产品线上是使用mysqli类或者框架自身的参数绑定的方式。拼 sql 的方式几年前已经交过学费了,不过感觉学费还是交的不够。。。
    iyaozhen
        67
    iyaozhen  
       2015-05-05 14:07:04 +08:00
    @est 非常抱歉,逻辑错误了。

    还有就是才疏学浅,以为都是使用 sql 直接判断的。
    WKPlus
        68
    WKPlus  
       2015-05-05 14:39:18 +08:00
    @est
    把你的密码设成 0x1234Ab,然后退出登录再登录,换密码 1193131 登录,如果登录成功,那么密码绝对是明文保存的没跑。

    这句话补充是不是这样:
    1. 把你的密码设成 0x1234Ab,然后退出登录再登录,换密码 1193131 登录,如果登录成功,那么密码绝对是明文保存的且密码对比的时候用的是php的==符号
    2. 但是如果密码比较的时候用的是===,那么就算是明文保存的,上述探测手段也是发现不了的
    est
        69
    est  
    OP
       2015-05-05 15:21:59 +08:00
    @WKPlus 第一句话也不完全一定。万一别人恰好特别写了 1193131 是万能登录密码呢?

    第二句话理论是这样的。 但是既然都知道用 === 怎么还会用明文密码。。。。。。。
    WKPlus
        70
    WKPlus  
       2015-05-05 19:50:59 +08:00
    @est 如果1193131是万能密码的话,你“把你的密码设成 0x1234Ab,然后退出登录再登录,换密码 1193131 登录,如果登录成功,那么密码绝对是明文保存的没跑”这句话就不成立了呀

    我的那两句解释只是想把你原来那句话的隐含意思说出来
    est
        71
    est  
    OP
       2015-05-05 20:15:48 +08:00
    @WKPlus 这不很容易解决么。把密码改成任意密码,如果1193131也能登录,那么说明1193131就是万能密码。


    准确的说,顶楼给出的几个密码对,可以衍生展开,如果尝试几组都符合特征,那么可以得到明文密码/md5无盐加密的结论。
    RemRain
        72
    RemRain  
       2015-05-05 22:40:54 +08:00
    @gDD 所以说 PHP 密码比较要这样:"X$pass1" == "X$pass2"
    gDD
        73
    gDD  
       2015-05-05 22:57:17 +08:00
    @RemRain 天……上面的帖子你都白看了吗?最次最次用 "$pass1" === "$pass2" 或者 strcmp(),最好用 hash_equals() 啊。
    123123
        74
    123123  
       2015-05-07 14:10:44 +08:00
    @gDD 只要最前方加个X就不会转换成数字进行比较,说的也没错就是了,不过加个=不是更方便么。。
    mahone3297
        75
    mahone3297  
       2015-05-07 22:08:33 +08:00
    这个帖子很赞,学习了。。。
    mingyun
        76
    mingyun  
       2015-05-11 21:40:00 +08:00
    果真脑洞打开,不过'240610708' ,'QNKCDZO'这种字符是怎么发现的?
    fhefh
        77
    fhefh  
       2015-10-17 21:48:14 +08:00
    学习了 mark~~
    wusuopuBUPT
        78
    wusuopuBUPT  
       2015-10-17 23:58:51 +08:00
    @est 原来如此!
    Kratoshy
        79
    Kratoshy  
       2015-12-08 15:16:31 +08:00
    var_dump(md5('240610708') === md5('QNKCDZO'));
    这个是 false 吧?
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   974 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 80ms · UTC 19:08 · PVG 03:08 · LAX 11:08 · JFK 14:08
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.