Security hole - library from cwd

sorry, I write in my native language (translated with google)

desktop editor searches and tries to load libraries from several places, and the search in the current directory is performed earlier than in the traditional places where these libraries are located

for example, a piece of the strace log with loading the libgcc_s.so.1 library


openat(AT_FDCWD, "/opt/onlyoffice/desktopeditors/libgcc_s.so.1", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/opt/onlyoffice/desktopeditors/converter/libgcc_s.so.1", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/opt/onlyoffice/desktopeditors/libgcc_s.so.1", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "tls/x86_64/x86_64/libgcc_s.so.1", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "tls/x86_64/libgcc_s.so.1", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "tls/x86_64/libgcc_s.so.1", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "tls/libgcc_s.so.1", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "x86_64/x86_64/libgcc_s.so.1", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "x86_64/libgcc_s.so.1", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "x86_64/libgcc_s.so.1", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "libgcc_s.so.1", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib64/libgcc_s.so.1", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\300-\0\0\0\0\0\0"..., 832) = 832
lseek(3, 92528, SEEK_SET)               = 92528
read(3, "\4\0\0\0\20\0\0\0\5\0\0\0GNU\0\2\0\0\300\4\0\0\0\3\0\0\0\0\0\0\0", 32) = 32
fstat(3, {st_mode=S_IFREG|0755, st_size=99688, ...}) = 0
lseek(3, 92528, SEEK_SET)               = 92528
read(3, "\4\0\0\0\20\0\0\0\5\0\0\0GNU\0\2\0\0\300\4\0\0\0\3\0\0\0\0\0\0\0", 32) = 32
mmap(NULL, 2192080, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fe665268000
mprotect(0x7fe66527f000, 2093056, PROT_NONE) = 0
mmap(0x7fe66547e000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x16000) = 0x7fe66547e000
close(3)                                = 0

The penultimate line of openat shows that onlyoffice tries to load libgcc_s.so.1 from the current directory, and then successfully picks it up from /lib64

An attacker can place his version of the libgcc_s.so.1 library (not only this one - the full list can be taken from the strace log) next to any document and get it loaded and executed with the rights of the user who opened the document.

for example, I copied the libgcc_s.so.1 library to the home directory of the test user and opened the document located there with onlyoffice.

strace output (partial):


openat(AT_FDCWD, "/opt/onlyoffice/desktopeditors/libgcc_s.so.1", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/opt/onlyoffice/desktopeditors/converter/libgcc_s.so.1", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/opt/onlyoffice/desktopeditors/libgcc_s.so.1", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "tls/x86_64/x86_64/libgcc_s.so.1", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "tls/x86_64/libgcc_s.so.1", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "tls/x86_64/libgcc_s.so.1", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "tls/libgcc_s.so.1", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "x86_64/x86_64/libgcc_s.so.1", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "x86_64/libgcc_s.so.1", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "x86_64/libgcc_s.so.1", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "libgcc_s.so.1", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\300-\0\0\0\0\0\0"..., 832) = 832
lseek(3, 92528, SEEK_SET)               = 92528
read(3, "\4\0\0\0\20\0\0\0\5\0\0\0GNU\0\2\0\0\300\4\0\0\0\3\0\0\0\0\0\0\0", 32) = 32
fstat(3, {st_mode=S_IFREG|0755, st_size=99688, ...}) = 0
getcwd("/home/test", 128)               = 11
lseek(3, 92528, SEEK_SET)               = 92528
read(3, "\4\0\0\0\20\0\0\0\5\0\0\0GNU\0\2\0\0\300\4\0\0\0\3\0\0\0\0\0\0\0", 32) = 32
mmap(NULL, 2192080, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7ff863223000
mprotect(0x7ff86323a000, 2093056, PROT_NONE) = 0
mmap(0x7ff863439000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x16000) = 0x7ff863439000
close(3)                                = 0

lsof output:

$ lsof +d ~
COMMAND      PID USER   FD   TYPE DEVICE SIZE/OFF    NODE NAME
pipewire  128360 test  cwd    DIR    8,3     4096 6688047 /home/test
dbus-brok 128397 test  cwd    DIR    8,3     4096 6688047 /home/test
dbus-brok 128398 test  cwd    DIR    8,3     4096 6688047 /home/test
pipewire- 128399 test  cwd    DIR    8,3     4096 6688047 /home/test
gvfsd     128451 test  cwd    DIR    8,3     4096 6688047 /home/test
bash      128566 test  cwd    DIR    8,3     4096 6688047 /home/test
DesktopEd 128828 test  cwd    DIR    8,3     4096 6688047 /home/test
DesktopEd 128828 test  mem    REG    8,3    99688 6688226 /home/test/libgcc_s.so.1
editors_h 128834 test  cwd    DIR    8,3     4096 6688047 /home/test
editors_h 128834 test  mem    REG    8,3    99688 6688226 /home/test/libgcc_s.so.1
editors_h 128844 test  cwd    DIR    8,3     4096 6688047 /home/test
editors_h 128844 test  mem    REG    8,3    99688 6688226 /home/test/libgcc_s.so.1
editors_h 128854 test  cwd    DIR    8,3     4096 6688047 /home/test
editors_h 128854 test  mem    REG    8,3    99688 6688226 /home/test/libgcc_s.so.1
editors_h 128856 test  cwd    DIR    8,3     4096 6688047 /home/test
editors_h 128856 test  mem    REG    8,3    99688 6688226 /home/test/libgcc_s.so.1
editors_h 128889 test  cwd    DIR    8,3     4096 6688047 /home/test
editors_h 128889 test  mem    REG    8,3    99688 6688226 /home/test/libgcc_s.so.1
lsof      128901 test  cwd    DIR    8,3     4096 6688047 /home/test
lsof      128902 test  cwd    DIR    8,3     4096 6688047 /home/test

Hello @alef

Thanks for reporting this scenario.
Our team is analyzing it.

Some of the content was hidden in terms of safety.

Based on this scenario we have created bug report number 60244.
Thank you very much for contributing to the security of our editors.

1 Like

Good afternoon, it’s been a month already - it’s time for me to register CVE

Hello again @alef

Security is the prior aim for us.
This bug is a major task and our team is working hard on fixing this issue as soon as possible.

hi. it’s a simple trojan horse

content of file evil.c:
Was hidden

content of file vers:
Was hidden

compile with the following command:
Was hidden

put the libselinux.so.1 library next to the document and check (in the console):
Was hidden

Hello @alef

Again thank you very much for the report.
We are checking the situation with that. I will let you know when any results come up.

Some of the content was hidden in terms of safety.

In addition, please specify on which version of Desktop Editors this vulnerability can be used. Is it the actual version 7.3.3?

Good afternoon. Judging by the commit KOROL dated 02/23/2023, you are on the right track. Tomorrow I will install version 7.3.3 and write the results of the check

Hello @alef

Gladly waiting for your results.

Hello. It’s ok, I checked

I’m sorry but does it meant that the trojan horse is not executable on the actual version?
Apologies if I misunderstand.

I confirm that the trojan does not work :slight_smile:

Thank you for the confirmation, I’m glad to hear that it doesn’t.