Upgrade to Pro — share decks privately, control downloads, hide ads and more …

OSSの脆弱性を探すためにやったこと

 OSSの脆弱性を探すためにやったこと

第19回セキュリティさくらの資料(前半だけ)です。

Teppei Fukuda

December 02, 2017
Tweet

More Decks by Teppei Fukuda

Other Decks in Programming

Transcript

  1. ࣗݾ঺հ • ෱ా మฏʢ@knqyf263ʣ • ޷͖ͳ΋ͷ • ωοτϫʔΫ • ηΩϡϦςΟ

    • ອը • ߪಡࡶࢽ • िץগ೥δϟϯϓ • िץগ೥ϚΨδϯ • िץগ೥αϯσʔ • िץϠϯάδϟϯϓ • δϟϯϓSQ • ผ࡭গ೥ϚΨδϯ • ଞɺ୯ߦຊଟ਺
  2. ੬ऑੑͷϨΠϠʔ • WebΞϓϦέʔγϣϯ • CGI, PHP, Java, etc • ϛυϧ΢ΣΞ

    • OpenSSH • Postfix, etc. • OS ʢWindows, LinuxͳͲʣ • Linux Kernel
  3. ੬ऑੑͷछྨ • WebΞϓϦέʔγϣϯ • XSS, SQLi, CSRF, etc. • ϛυϧ΢ΣΞ

    • ೚ҙίʔυ࣮ߦ, ೝূճආ, etc. • OS ʢWindows, LinuxͳͲʣ • ݖݶঢ֨, DoS, etc.
  4. ࣗ෼ͷ৔߹ • ޷͖ͳϓϩτίϧ • DNS • ޷͖ͳιϑτ΢ΣΞ • BIND •

    ޷͖ͳ੬ऑੑ • DoS BINDͷDoS ୯७ͳ%P4ͳͷʹ க໋తͳײ͕͡޷͖
  5. ޷͖ͳ΋ͷ͔Β୳࢝͠ΊΔ ྫ • ޷͖ͳϓϩτίϧ • SSL/TLS • ޷͖ͳιϑτ΢ΣΞ • OpenSSL

    • ޷͖ͳ੬ऑੑ • ೚ҙίʔυ࣮ߦʢRCE) աڈͷ੬ऑੑͱ ࣅͨ΋ͷ͕ͳ͍͔
  6. ޷͖ͳ΋ͷ͔Β୳࢝͠ΊΔ ྫ • ޷͖ͳϓϩτίϧ • SSL/TLS • ޷͖ͳιϑτ΢ΣΞ • OpenSSL

    • ޷͖ͳ੬ऑੑ • ଞͷ੬ऑੑ΋୳ͯ͠ΈΔ • DoS΍҉߸ͷ࣮૷ෆඋ΋աڈʹݟ͔͍ͭͬͯΔ
  7. ࣗ෼ͷ৔߹ • ޷͖ͳϓϩτίϧ • DNS • ޷͖ͳιϑτ΢ΣΞ • DNSܥͷιϑτ΢ΣΞΛ୳ͯ͠ΈΔ •

    https://github.com/miekg/dns • https://github.com/kenshinx/godns • ޷͖ͳ੬ऑੑ • DoS ࠷ۙ(PΛॻ͘͜ͱ͕ଟ͍ͷͰ (PͰॻ͔Εͨ΋ͷ͔Β୳͢
  8. ࣮ࡍʹಈ͔ͯ͠ΈΔ $./packetbeat -N -e 2017/12/01 04:03:08.679303 metrics.go:23: INFO Metrics logging

    every 30s 2017/12/01 04:03:08.679117 beat.go:297: INFO Home path: [/root/ packetbeat-5.6.3-linux-x86_64] Config path: [/root/packetbeat-5.6.3-linux- x86_64] Data path: [/root/packetbeat-5.6.3-linux-x86_64/data] Logs path: [/ root/packetbeat-5.6.3-linux-x86_64/logs] 2017/12/01 04:03:08.680873 beat.go:192: INFO Setup Beat: packetbeat; Version: 5.6.3 2017/12/01 04:03:08.680879 publish.go:217: INFO Dry run mode. All output types except the file based one are disabled. ... (தུʣ... 2017/12/01 04:03:08.681143 protos.go:89: INFO registered protocol plugin: mysql 2017/12/01 04:03:08.681145 protos.go:89: INFO registered protocol plugin: nfs 2017/12/01 04:03:08.681148 protos.go:89: INFO registered protocol plugin: pgsql 2017/12/01 04:03:08.681165 protos.go:89: INFO registered protocol plugin: redis 2017/12/01 04:03:08.707989 beat.go:233: INFO packetbeat start running.
  9. PostgreSQLϓϩτίϧͷύʔεॲཧ func pgsqlFieldsParser(s *pgsqlStream, buf []byte) error { ...ʢதུʣ... //

    read Type OID (int32) off += 4 // read column length (int16) off += 2 // read type modifier (int32) off += 4 // read format (int16) format := common.BytesNtohs(buf[off : off+2]) off += 2 fieldsFormat = append(fieldsFormat, byte(format)) } ഑ྻͷΠϯσοΫεͷ ࢦఆ͕ؾʹͳΔ bufʹ͸Կ͕ೖΔʁ
  10. ιʔείʔυͷྲྀΕΛ௥͏ QHTRM'JFMET1BSTFS QBSTF3PX%FTDSJQUJPO QBSTF$PNNBOE func (pgsql *pgsqlPlugin) parseCommand(s *pgsqlStream) (bool,

    bool) { // read type typ := byte(s.data[s.parseOffset]) ... switch typ { case 'Q': return pgsql.parseSimpleQuery(s, length) case 'T': return pgsql.parseRowDescription(s, length) ... } ύέοτͷCZUF໨͕ `5ͷͱ͖ʹݺ͹ΕΔॲཧ
  11. testdb=# SELECT * FROM test; id | body ----+------ 1

    | test (1 row) RowDescription 3PX%FTDSJQUJPO • parseRowDescription • ͦ΋ͦ΋RowDescriptionͱ͸ʁ
  12. RowDescription • Byte1('T') • ϝοηʔδ͕ߦͷهड़Ͱ͋Δ͜ͱΛࣝผ͠·͢ɻ • Int32 • ࣗ਎ΛؚΉɺϝοηʔδ಺༰ͷ௕͞ʢόΠτ୯Ґʣɻ •

    Int16 • ߦ಺ͷϑΟʔϧυ਺Λࢦఆ͠·͢ ʢθϩͱ͢Δ͜ͱ͕Ͱ͖·͢ʣɻ • ͦͷޙɺ֤ϑΟʔϧυʹରͯ͠ҎԼ͕ଓ͖·͢ɻ • String • ϑΟʔϧυ໊Ͱ͢ɻ • Int32 • ϑΟʔϧυ͕ಛఆͷςʔϒϧͷྻͱͯࣝ͠ผͰ͖Δ৔߹ɺςʔϒϧͷΦϒδΣΫτIDͰ͢ɻ ͞΋ͳ͘͹θϩͰ͢ɻ • Int16 • ϑΟʔϧυ͕ಛఆͷςʔϒϧͷྻͱͯࣝ͠ผͰ͖Δ৔߹ɺྻͷଐੑ൪߸Ͱ͢ɻ ͞΋ͳ͘͹θϩͰ͢ɻ • Int32 • ϑΟʔϧυͷσʔλܕͷΦϒδΣΫτIDͰ͢ɻ • Int16 • σʔλܕͷେ͖͞ʢpg_type.typlenΛࢀরʣͰ͢ɻ ෛͷ஋͕Մม௕ͷܕΛද͢͜ͱʹ஫ҙ͍ͯͩ͘͠͞ɻ • Int32 • ܕम০ࢠʢpg_attribute.atttypmodΛࢀরʣͰ͢ɻ म০ࢠͷҙຯ͸ܕʹݻ༗Ͱ͢ɻ • Int16 • ϑΟʔϧυʹ࢖༻͞ΕΔॻࣜίʔυͰ͢ɻݱࡏɺ0ʢςΩετʣ·ͨ͸1ʢόΠφϦʣͷ͍ͣΕ͔ʹͳΓ·͢ɻ https://www.postgresql.jp/document/9.6/html/protocol-message-formats.htm
  13. testdb=# SELECT * FROM test; id | body ----+------ 1

    | test --- 54 00 00 00 32 00 02 69 64 00 00 00 45 0e 00 01 00 00 00 17 00 04 ff ff ff ff 00 00 62 6f 64 79 00 00 00 45 0e 00 02 00 00 00 19 ff ff ff ff ff ff 00 00 --- 54 ! 'T'ͳͷͰRowDescription 00 00 00 32 ! ௕͞=50Λҙຯ͢Δ 00 02 ! ϑΟʔϧυ਺=2Λҙຯ͢Δ 69 64 00 ! "id" 00 00 45 0e ! ςʔϒϧͷΦϒδΣΫτID(17678) 00 01 ! ྻͷଐੑ൪߸ ... 00 00 ! ϑΟʔϧυʹ࢖༻͞ΕΔॻࣜίʔυʢςΩετͷ৔߹͸0ʣ RowDescription CVG<P⒎P⒎ > ͷॲཧ͸͜͜ʂ
  14. // Test parsing a response with data attached func TestPgsqlParser_dataResponse(t

    *testing.T) { if testing.Verbose() { logp.LogInit(logp.LOG_DEBUG, "", false, true, []string{"pgsql", "pgsqldetailed"}) } pgsql := pgsqlModForTests() data := []byte( “5400000033000269640000008fc40001000000170004ffffffff000076616c75650000008fc400020000001 9ffffffffffff0000" + "44000000130002000000013100000004746f746f" + "440000001500020000000133000000066d617274696e" + "440000001300020000000134000000046a65616e" + "430000000b53454c45435400" + "5a0000000549") message, err := hex.DecodeString(string(data)) if err != nil { t.Error("Failed to decode hex string") } stream := &pgsqlStream{data: message, message: new(pgsqlMessage)} ok, complete := pgsql.pgsqlMessageParser(stream) ςετίʔυ ͜͜Λ͍ͬͯ͡ΈΔ
  15. // Test parsing a response with data attached func TestPgsqlParser_dataResponse(t

    *testing.T) { if testing.Verbose() { logp.LogInit(logp.LOG_DEBUG, "", false, true, []string{"pgsql", "pgsqldetailed"}) } pgsql := pgsqlModForTests() data := []byte( "540000001b00016964000000450e0001000000170004ffffffff0000") message, err := hex.DecodeString(string(data)) if err != nil { t.Error("Failed to decode hex string") } stream := &pgsqlStream{data: message, message: new(pgsqlMessage)} ok, complete := pgsql.pgsqlMessageParser(stream) ςετίʔυ ਖ਼ৗͳ஋ΛೖΕͯΈΔ
  16. // Test parsing a response with data attached func TestPgsqlParser_dataResponse(t

    *testing.T) { if testing.Verbose() { logp.LogInit(logp.LOG_DEBUG, "", false, true, []string{"pgsql", "pgsqldetailed"}) } pgsql := pgsqlModForTests() data := []byte( "540000001b00016964000000450e0001000000170004ffffffff0000") message, err := hex.DecodeString(string(data)) if err != nil { t.Error("Failed to decode hex string") } stream := &pgsqlStream{data: message, message: new(pgsqlMessage)} ok, complete := pgsql.pgsqlMessageParser(stream) ෆਖ਼ͳೖྗ஋ʹม͑Δ CVG<P⒎P⒎ >͸ CZUFલఏͳͷͰ ࡟ͬͨΒམͪͦ͏
  17. $ cd ~/go/src/github.com/elastic/beats/packetbeat/protos/pgsql $ go test -run TestPgsqlParser_dataResponse PASS ok

    github.com/elastic/beats/packetbeat/protos/pgsql 0.085s མͪͳ͔ͬͨ ςετίʔυΛ࣮ߦͯ͠ΈΔ
  18. ͜ͷՕॴ͸ݺ͹Ε͍ͯͳ͔ͬͨ printfσόοάͯ͠ΈΔ func (pgsql *pgsqlPlugin) parseCommand(s *pgsqlStream) (bool, bool) {

    // read type typ := byte(s.data[s.parseOffset]) ... case 'T': + fmt.Printf("%d\n", length) return pgsql.parseRowDescription(s, length) ... } ଞͷՕॴͷΤϥʔॲཧͰ஄͔Ε͍ͯΔ
  19. ௕͞ͷൺֱ if len(s.data[s.parseOffset:]) <= length { detailedf("Wait for more data")

    return true, false } σʔλͷ࣮ࡍͷ௕͞ cc CZUF ύέοτ಺ͷهड़ cc CZUF 54 00 00 00 1b ... • ҎԼͷνΣοΫͰ஄͔Ε͍ͯͨ
  20. // Test parsing a response with data attached func TestPgsqlParser_dataResponse(t

    *testing.T) { if testing.Verbose() { logp.LogInit(logp.LOG_DEBUG, "", false, true, []string{"pgsql", "pgsqldetailed"}) } pgsql := pgsqlModForTests() data := []byte( "540000001b00016964000000450e0001000000170004ffffffff0000") message, err := hex.DecodeString(string(data)) if err != nil { t.Error("Failed to decode hex string") } stream := &pgsqlStream{data: message, message: new(pgsqlMessage)} ok, complete := pgsql.pgsqlMessageParser(stream) ௕͞Λἧ͑Δ ࡟Δ CZUFݮΒ͢ B
  21. $ go test -run TestPgsqlParser_dataResponse panic: runtime error: slice bounds

    out of range [recovered] panic: runtime error: slice bounds out of range goroutine 20 [running]: testing.tRunner.func1(0xc420068820) /usr/lib/go-1.8/src/testing/testing.go:622 +0x29d panic(0x9bc500, 0xe46af0) /usr/lib/go-1.8/src/runtime/panic.go:489 +0x2cf github.com/elastic/beats/packetbeat/protos/pgsql.pgsqlFieldsParser(0xc420035f60, 0xc421164f05, 0x16, 0x16, 0x0, 0x0) /root/go/src/github.com/elastic/beats/packetbeat/protos/pgsql/parse.go:384 +0x6c6 ... (தུ) ... created by testing.(*T).Run /usr/lib/go-1.8/src/testing/testing.go:697 +0x2ca exit status 2 FAIL github.com/elastic/beats/packetbeat/protos/pgsql 0.084s མͪͨʂʂ ςετίʔυΛ࣮ߦͯ͠ΈΔ
  22. $ echo -e "T\x00\x00\x00\x1a\(ࣗॗʣxff\xff\xff\xff\x00" | nc 127.0.0.1 5432 ؆୯ ύέοτΛ1ͭ౤͛Δ͚ͩͰམͪΔ

    # ./packetbeat -N -e ... 2017/12/04 04:45:22.465965 log.go:145: ERR Stacktrace: goroutine 13 [running]: runtime/debug.Stack(0xbd68c4, 0x2b, 0xc421249560) /usr/local/go/src/runtime/debug/stack.go:24 +0x79 github.com/elastic/beats/libbeat/logp.Recover(0xbc366f, 0x14) /go/src/github.com/elastic/beats/libbeat/logp/log.go:145 +0x138 panic(0xada5c0, 0xc4200100f0) /usr/local/go/src/runtime/panic.go:458 +0x243 github.com/elastic/beats/packetbeat/protos/pgsql.pgsqlFieldsParser(0xc4211e8b00, 0xc421210749, 0x2f, 0x36, 0xbba4b1, 0xd) /go/src/github.com/elastic/beats/packetbeat/protos/pgsql/parse.go:382 +0x53c ...