Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SystemSan: arbitrary DNS resolution detection #9119

Merged
merged 9 commits into from
Dec 6, 2022

Conversation

catenacyber
Copy link
Contributor

cc @oliverchang @alan32liu after #9100 and #8448

After compiling locally, I can see that
./SystemSan ./target_dns -dict=vuln.dict
crashes in a few seconds with

===BUG DETECTED: Arbitrary domain name resolution===
===Domain resolved: .f.z===
===DNS request type: 0, class: 256===
==315== ERROR: libFuzzer: deadly signal
    #0 0x539131 in __sanitizer_print_stack_trace /src/llvm-project/compiler-rt/lib/asan/asan_stack.cpp:87:3
    #1 0x457c48 in fuzzer::PrintStackTrace() /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerUtil.cpp:210:5
    #2 0x43c923 in fuzzer::Fuzzer::CrashCallback() /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:233:3
    #3 0x7fa57940041f  (/lib/x86_64-linux-gnu/libpthread.so.0+0x1441f) (BuildId: 7b4536f41cdaa5888408e82d0836e33dcf436466)
    #4 0x7fa5793ff7db in send (/lib/x86_64-linux-gnu/libpthread.so.0+0x137db) (BuildId: 7b4536f41cdaa5888408e82d0836e33dcf436466)
    #5 0x503ba4 in __interceptor_send /src/llvm-project/compiler-rt/lib/asan/../sanitizer_common/sanitizer_common_interceptors.inc:6802:17
    #6 0x7fa578abf462  (/lib/x86_64-linux-gnu/libresolv.so.2+0xb462) (BuildId: 4519041bde5b859c55798ac0745b0b6199cb7d94)
    #7 0x7fa578abbc43 in __res_context_query (/lib/x86_64-linux-gnu/libresolv.so.2+0x7c43) (BuildId: 4519041bde5b859c55798ac0745b0b6199cb7d94)
    #8 0x7fa578abc8ed in __res_context_search (/lib/x86_64-linux-gnu/libresolv.so.2+0x88ed) (BuildId: 4519041bde5b859c55798ac0745b0b6199cb7d94)
    #9 0x7fa578ad2cc1  (/lib/x86_64-linux-gnu/libnss_dns.so.2+0x2cc1) (BuildId: 3fac4ec397ba8e8938fe298f103113f315465130)
    #10 0x7fa578ad2e8b in _nss_dns_gethostbyname3_r (/lib/x86_64-linux-gnu/libnss_dns.so.2+0x2e8b) (BuildId: 3fac4ec397ba8e8938fe298f103113f315465130)
    #11 0x7fa578ad2f41 in _nss_dns_gethostbyname2_r (/lib/x86_64-linux-gnu/libnss_dns.so.2+0x2f41) (BuildId: 3fac4ec397ba8e8938fe298f103113f315465130)
    #12 0x7fa5792fdc9d in gethostbyname2_r (/lib/x86_64-linux-gnu/libc.so.6+0x130c9d) (BuildId: 1878e6b475720c7c51969e69ab2d276fae6d1dee)
    #13 0x7fa5792d179e  (/lib/x86_64-linux-gnu/libc.so.6+0x10479e) (BuildId: 1878e6b475720c7c51969e69ab2d276fae6d1dee)
    #14 0x7fa5792d2f58 in getaddrinfo (/lib/x86_64-linux-gnu/libc.so.6+0x105f58) (BuildId: 1878e6b475720c7c51969e69ab2d276fae6d1dee)
    #15 0x4d93ac in getaddrinfo /src/llvm-project/compiler-rt/lib/asan/../sanitizer_common/sanitizer_common_interceptors.inc:2667:13
    #16 0x56c8d9 in LLVMFuzzerTestOneInput /out/SystemSan/target_dns.cpp:35:11
    #17 0x43dec3 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:611:15
    #18 0x43d6aa in fuzzer::Fuzzer::RunOne(unsigned char const*, unsigned long, bool, fuzzer::InputInfo*, bool, bool*) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:514:3
    #19 0x43ed79 in fuzzer::Fuzzer::MutateAndTestOne() /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:757:19
    #20 0x43fa45 in fuzzer::Fuzzer::Loop(std::__Fuzzer::vector<fuzzer::SizedFile, std::__Fuzzer::allocator<fuzzer::SizedFile> >&) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:895:5
    #21 0x42edaf in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerDriver.cpp:912:6
    #22 0x458402 in main /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerMain.cpp:20:10
    #23 0x7fa5791f1082 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x24082) (BuildId: 1878e6b475720c7c51969e69ab2d276fae6d1dee)
    #24 0x41f7ed in _start (/out/SystemSan/target_dns+0x41f7ed)

NOTE: libFuzzer has rudimentary signal handlers.
      Combine libFuzzer with AddressSanitizer or similar for better crash reports.
SUMMARY: libFuzzer: deadly signal
MS: 2 CrossOver-ManualDict- DE: "f.z"-; base unit: ac3478d69a3c81fa62e60f5c3696165a4e5e6ac4
0x66,0x2e,0x7a,
f.z
artifact_prefix='./'; Test unit written to ./crash-926813b2d6adde373f96a10594a5314951588384
Base64: Zi56

You can also try

echo -n f.z > toto
./SystemSan ./target_dns toto  

@oliverchang
Copy link
Collaborator

Thanks! This still doesn't work for me. Perhaps there's a difference in the DNS request params here?

@jonathanmetzman can you help debug as well?

root@09785891326e:/work# ./SystemSan ./target_dns toto
INFO: Running with entropic power schedule (0xFF, 100).
INFO: Seed: 2288191501
INFO: Loaded 1 modules   (21 inline 8-bit counters): 21 [0x5e7fe0, 0x5e7ff5), 
INFO: Loaded 1 PC tables (21 PCs): 21 [0x5a58b0,0x5a5a00), 
./target_dns: Running 1 inputs 1 time(s) each.
Running: toto
INPUTf.z
INPUTf.z
Executed toto in 975 ms
***
*** NOTE: fuzzing was not performed, you have only
***       executed the target code on a fixed set of inputs.
***
==39==LeakSanitizer has encountered a fatal error.
==39==HINT: For debugging, try setting environment variable LSAN_OPTIONS=v

@catenacyber
Copy link
Contributor Author

Thanks @oliverchang

Could you give your output for strace ./target_dns toto ?

You need to installs trace first with apt-get install -y strace

For instance, mine contains these lines

openat(AT_FDCWD, "/etc/hosts", O_RDONLY|O_CLOEXEC) = 3
socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, IPPROTO_IP) = 3
connect(3, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("10.194.3.12")}, 16) = 0
sendto(3, "\353/\1\0\0\1\0\0\0\0\0\0\1f\1z\0\0\1\0\1", 21, MSG_NOSIGNAL, NULL, 0) = 21

@oliverchang
Copy link
Collaborator

Thakns @catenacyber .

I see this:

connect(3, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("8.8.8.8")}, 16) = 0
poll([{fd=3, events=POLLOUT}], 1, 0)    = 1 ([{fd=3, revents=POLLOUT}])
sendto(3, "\24a\1 \0\1\0\0\0\0\0\1\1f\1z\3RED\4REDA\6REDACT"..., 52, MSG_NOSIGNAL, NULL, 0) = 52

@catenacyber
Copy link
Contributor Author

Thanks @oliverchang

Are there other strings than READACTED in reality ?

It looks like you redoing a dns resolution for f.z.RED.REDA.READACTED etc... where I think this is a domain reputation tool or something like it...
Is it how it is run on oss-fuzz ?

@oliverchang
Copy link
Collaborator

Thanks @oliverchang

Are there other strings than READACTED in reality ?

It looks like you redoing a dns resolution for f.z.RED.REDA.READACTED etc... where I think this is a domain reputation tool or something like it... Is it how it is run on oss-fuzz ?

No, it's not how it's run on oss-fuzz, just my local environment.

Is there a reason why this case didn't work for me? Is there a way to generalise this sanitizer such that this works in more environments?

@jonathanmetzman
Copy link
Contributor

jonathanmetzman commented Dec 5, 2022

This also does not work for me. Interestingly this program reports a memory leak under LSAN.

@oliverchang
Copy link
Collaborator

This also does not work for me. Interestingly this program reports a memory leak under LSAN.

LSAN is incompatible with ptrace, so it needs to be disabled.

I just did some quick debugging and it looks like the cause for me of this not getting reported is the h.additional part of this check:

if (h.answers != 0 || h.nameservers != 0 || h.additional != 0) {

h.additional is 1 on my machine. Is there any reason we need to filter this out and require this to be 0 ?

@oliverchang
Copy link
Collaborator

This also does not work for me. Interestingly this program reports a memory leak under LSAN.

LSAN is incompatible with ptrace, so it needs to be disabled.

I just did some quick debugging and it looks like the cause for me of this not getting reported is the h.additional part of this check:

if (h.answers != 0 || h.nameservers != 0 || h.additional != 0) {

h.additional is 1 on my machine. Is there any reason we need to filter this out and require this to be 0 ?

I'll change this check to > 1 instead of != 0. @catenacyber let me know if there are any problems with this.

@catenacyber
Copy link
Contributor Author

I'll change this check to > 1 instead of != 0

It is good.
I would even have removed || h.additional != 0 to relax it even more.

@jonathanmetzman
Copy link
Contributor

This also does not work for me. Interestingly this program reports a memory leak under LSAN.

LSAN is incompatible with ptrace, so it needs to be disabled.
I just did some quick debugging and it looks like the cause for me of this not getting reported is the h.additional part of this check:

if (h.answers != 0 || h.nameservers != 0 || h.additional != 0) {

h.additional is 1 on my machine. Is there any reason we need to filter this out and require this to be 0 ?

I'll change this check to > 1 instead of != 0. @catenacyber let me know if there are any problems with this.

This fix works for me now

@jonathanmetzman jonathanmetzman merged commit a857bfb into google:master Dec 6, 2022
@catenacyber
Copy link
Contributor Author

Thanks for merging :-)

@jonathanmetzman
Copy link
Contributor

@catenacyber have you checked if this can catch any known vulnerabilities and what are they?

eamonnmcmanus pushed a commit to eamonnmcmanus/oss-fuzz that referenced this pull request Mar 15, 2023
cc @oliverchang @alan32liu after google#9100 and google#8448

After compiling locally, I can see that
`./SystemSan ./target_dns -dict=vuln.dict`
crashes in a few seconds with
```
===BUG DETECTED: Arbitrary domain name resolution===
===Domain resolved: .f.z===
===DNS request type: 0, class: 256===
==315== ERROR: libFuzzer: deadly signal
    #0 0x539131 in __sanitizer_print_stack_trace /src/llvm-project/compiler-rt/lib/asan/asan_stack.cpp:87:3
    google#1 0x457c48 in fuzzer::PrintStackTrace() /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerUtil.cpp:210:5
    google#2 0x43c923 in fuzzer::Fuzzer::CrashCallback() /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:233:3
    google#3 0x7fa57940041f  (/lib/x86_64-linux-gnu/libpthread.so.0+0x1441f) (BuildId: 7b4536f41cdaa5888408e82d0836e33dcf436466)
    google#4 0x7fa5793ff7db in send (/lib/x86_64-linux-gnu/libpthread.so.0+0x137db) (BuildId: 7b4536f41cdaa5888408e82d0836e33dcf436466)
    google#5 0x503ba4 in __interceptor_send /src/llvm-project/compiler-rt/lib/asan/../sanitizer_common/sanitizer_common_interceptors.inc:6802:17
    google#6 0x7fa578abf462  (/lib/x86_64-linux-gnu/libresolv.so.2+0xb462) (BuildId: 4519041bde5b859c55798ac0745b0b6199cb7d94)
    google#7 0x7fa578abbc43 in __res_context_query (/lib/x86_64-linux-gnu/libresolv.so.2+0x7c43) (BuildId: 4519041bde5b859c55798ac0745b0b6199cb7d94)
    google#8 0x7fa578abc8ed in __res_context_search (/lib/x86_64-linux-gnu/libresolv.so.2+0x88ed) (BuildId: 4519041bde5b859c55798ac0745b0b6199cb7d94)
    google#9 0x7fa578ad2cc1  (/lib/x86_64-linux-gnu/libnss_dns.so.2+0x2cc1) (BuildId: 3fac4ec397ba8e8938fe298f103113f315465130)
    google#10 0x7fa578ad2e8b in _nss_dns_gethostbyname3_r (/lib/x86_64-linux-gnu/libnss_dns.so.2+0x2e8b) (BuildId: 3fac4ec397ba8e8938fe298f103113f315465130)
    google#11 0x7fa578ad2f41 in _nss_dns_gethostbyname2_r (/lib/x86_64-linux-gnu/libnss_dns.so.2+0x2f41) (BuildId: 3fac4ec397ba8e8938fe298f103113f315465130)
    google#12 0x7fa5792fdc9d in gethostbyname2_r (/lib/x86_64-linux-gnu/libc.so.6+0x130c9d) (BuildId: 1878e6b475720c7c51969e69ab2d276fae6d1dee)
    google#13 0x7fa5792d179e  (/lib/x86_64-linux-gnu/libc.so.6+0x10479e) (BuildId: 1878e6b475720c7c51969e69ab2d276fae6d1dee)
    google#14 0x7fa5792d2f58 in getaddrinfo (/lib/x86_64-linux-gnu/libc.so.6+0x105f58) (BuildId: 1878e6b475720c7c51969e69ab2d276fae6d1dee)
    google#15 0x4d93ac in getaddrinfo /src/llvm-project/compiler-rt/lib/asan/../sanitizer_common/sanitizer_common_interceptors.inc:2667:13
    google#16 0x56c8d9 in LLVMFuzzerTestOneInput /out/SystemSan/target_dns.cpp:35:11
    google#17 0x43dec3 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:611:15
    google#18 0x43d6aa in fuzzer::Fuzzer::RunOne(unsigned char const*, unsigned long, bool, fuzzer::InputInfo*, bool, bool*) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:514:3
    google#19 0x43ed79 in fuzzer::Fuzzer::MutateAndTestOne() /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:757:19
    google#20 0x43fa45 in fuzzer::Fuzzer::Loop(std::__Fuzzer::vector<fuzzer::SizedFile, std::__Fuzzer::allocator<fuzzer::SizedFile> >&) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:895:5
    google#21 0x42edaf in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerDriver.cpp:912:6
    google#22 0x458402 in main /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerMain.cpp:20:10
    google#23 0x7fa5791f1082 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x24082) (BuildId: 1878e6b475720c7c51969e69ab2d276fae6d1dee)
    google#24 0x41f7ed in _start (/out/SystemSan/target_dns+0x41f7ed)

NOTE: libFuzzer has rudimentary signal handlers.
      Combine libFuzzer with AddressSanitizer or similar for better crash reports.
SUMMARY: libFuzzer: deadly signal
MS: 2 CrossOver-ManualDict- DE: "f.z"-; base unit: ac3478d69a3c81fa62e60f5c3696165a4e5e6ac4
0x66,0x2e,0x7a,
f.z
artifact_prefix='./'; Test unit written to ./crash-926813b2d6adde373f96a10594a5314951588384
Base64: Zi56
```

You can also try
```
echo -n f.z > toto
./SystemSan ./target_dns toto  
```

Co-authored-by: Oliver Chang <oliverchang@users.noreply.github.com>
Co-authored-by: jonathanmetzman <31354670+jonathanmetzman@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants